2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * C++ DDF abstraction for interpretive RPC
28 #include "remoting/ddf.h"
31 # define snprintf _snprintf
35 #include <xercesc/dom/DOM.hpp>
36 #include <xercesc/util/XMLUniDefs.hpp>
37 #include <xmltooling/XMLToolingConfig.h>
38 #include <xmltooling/util/ParserPool.h>
39 #include <xmltooling/util/URLEncoder.h>
40 #include <xmltooling/util/XMLHelper.h>
42 using namespace shibsp;
43 using namespace xmltooling;
44 using namespace xercesc;
47 // defensive string functions
49 size_t ddf_strlen(const char* s)
51 return s ? strlen(s) : 0;
54 char* ddf_strdup(const char* s)
56 return (s && *s) ? strdup(s) : nullptr;
59 #define MAX_NAME_LEN 255
61 /* Parses '.' notation paths, where each component is at most MAX_NAME_LEN long.
62 path contains the address of a constant string which is the current path.
63 name points to a buffer in which to place the first path component.
64 After execution, the path pointer will be moved past the first dot.
65 The actual path string is never modified. Only name is written to.
66 The name buffer is returned from the function. */
67 char* ddf_token(const char** path, char* name)
70 if (*path==nullptr || **path==0)
73 const char* temp=strchr(*path,'.');
75 strncpy(name,*path,MAX_NAME_LEN);
79 else if (temp>*path) {
80 strncpy(name,*path,temp-*path);
89 // body implementation
91 struct shibsp::ddf_body_t {
92 ddf_body_t() : name(nullptr), parent(nullptr), next(nullptr), prev(nullptr), type(DDF_EMPTY) {}
94 char* name; // name of node
95 ddf_body_t* parent; // parent node, if any
96 ddf_body_t* next; // next node, if any
97 ddf_body_t* prev; // previous node, if any
108 } type; // data type of node
121 } value; // value of node
124 // library implementation
126 DDF::DDF() : m_handle(nullptr)
130 DDF::DDF(const char* n)
132 m_handle=new(nothrow) ddf_body_t;
136 DDF::DDF(const char* n, const char* val, bool safe)
138 m_handle=new(nothrow) ddf_body_t;
140 string(const_cast<char*>(val), true, safe);
143 DDF::DDF(const char* n, long val)
145 m_handle=new(nothrow) ddf_body_t;
150 DDF::DDF(const char* n, double val)
152 m_handle=new(nothrow) ddf_body_t;
157 DDF::DDF(const char* n, void* val)
159 m_handle=new(nothrow) ddf_body_t;
166 remove().empty().name(nullptr);
172 DDF DDF::copy() const
174 if (m_handle==nullptr)
177 switch (m_handle->type) {
178 case ddf_body_t::DDF_EMPTY:
179 return DDF(m_handle->name);
180 case ddf_body_t::DDF_STRING:
181 case ddf_body_t::DDF_STRING_UNSAFE:
182 return DDF(m_handle->name,m_handle->value.string,(m_handle->type==ddf_body_t::DDF_STRING));
183 case ddf_body_t::DDF_INT:
184 return DDF(m_handle->name,m_handle->value.integer);
185 case ddf_body_t::DDF_FLOAT:
186 return DDF(m_handle->name,m_handle->value.floating);
187 case ddf_body_t::DDF_POINTER:
188 return DDF(m_handle->name,m_handle->value.pointer);
189 case ddf_body_t::DDF_STRUCT:
190 case ddf_body_t::DDF_LIST:
192 DDF copy(m_handle->name), temp;
193 if (m_handle->type==ddf_body_t::DDF_STRUCT)
197 ddf_body_t* child=m_handle->value.children.first;
200 DDF temp2=temp.copy();
202 if (copy.m_handle==nullptr)
204 if (m_handle->value.children.current==child)
205 copy.m_handle->value.children.current=copy.m_handle->value.children.last;
214 const char* DDF::name() const
216 return (m_handle) ? m_handle->name : nullptr;
219 DDF& DDF::name(const char* name)
221 char trunc_name[MAX_NAME_LEN+1]="";
225 free(m_handle->name);
227 strncpy(trunc_name,name,MAX_NAME_LEN);
228 trunc_name[MAX_NAME_LEN]='\0';
229 m_handle->name=ddf_strdup(trunc_name);
234 m_handle->name=nullptr;
239 bool DDF::isnull() const
241 return m_handle ? false : true;
244 bool DDF::isempty() const
246 return m_handle ? (m_handle->type==ddf_body_t::DDF_EMPTY) : false;
249 bool DDF::isstring() const
251 return m_handle ? (m_handle->type==ddf_body_t::DDF_STRING || m_handle->type==ddf_body_t::DDF_STRING_UNSAFE) : false;
254 bool DDF::isint() const
256 return m_handle ? (m_handle->type==ddf_body_t::DDF_INT) : false;
259 bool DDF::isfloat() const
261 return m_handle ? (m_handle->type==ddf_body_t::DDF_FLOAT) : false;
264 bool DDF::isstruct() const
266 return m_handle ? (m_handle->type==ddf_body_t::DDF_STRUCT) : false;
269 bool DDF::islist() const
271 return m_handle ? (m_handle->type==ddf_body_t::DDF_LIST) : false;
274 bool DDF::ispointer() const
276 return m_handle ? (m_handle->type==ddf_body_t::DDF_POINTER) : false;
279 const char* DDF::string() const
281 return isstring() ? m_handle->value.string : nullptr;
284 long DDF::integer() const
287 switch(m_handle->type) {
288 case ddf_body_t::DDF_INT:
289 return m_handle->value.integer;
290 case ddf_body_t::DDF_FLOAT:
291 return static_cast<long>(m_handle->value.floating);
292 case ddf_body_t::DDF_STRING:
293 case ddf_body_t::DDF_STRING_UNSAFE:
294 return m_handle->value.string ? atol(m_handle->value.string) : 0;
295 case ddf_body_t::DDF_STRUCT:
296 case ddf_body_t::DDF_LIST:
297 return m_handle->value.children.count;
303 double DDF::floating() const
306 switch(m_handle->type) {
307 case ddf_body_t::DDF_INT:
308 return m_handle->value.integer;
309 case ddf_body_t::DDF_FLOAT:
310 return m_handle->value.floating;
311 case ddf_body_t::DDF_STRING:
312 case ddf_body_t::DDF_STRING_UNSAFE:
313 return m_handle->value.string ? atof(m_handle->value.string) : 0;
314 case ddf_body_t::DDF_STRUCT:
315 case ddf_body_t::DDF_LIST:
316 return m_handle->value.children.count;
322 void* DDF::pointer() const
324 return ispointer() ? m_handle->value.pointer : nullptr;
327 size_t DDF::strlen() const
329 return ddf_strlen(string());
332 bool DDF::operator==(const char* s) const
334 if (string()==nullptr || s==nullptr)
335 return (string()==nullptr && s==nullptr);
337 return (::strcmp(string(),s)==0);
343 switch (m_handle->type) {
344 case ddf_body_t::DDF_STRING:
345 case ddf_body_t::DDF_STRING_UNSAFE:
346 if (m_handle->value.string)
347 free(m_handle->value.string);
349 case ddf_body_t::DDF_LIST:
350 case ddf_body_t::DDF_STRUCT:
353 while (m_handle->value.children.first)
355 temp.m_handle=m_handle->value.children.first;
360 m_handle->type=ddf_body_t::DDF_EMPTY;
365 DDF& DDF::string(char* val, bool copyit, bool safe)
367 if (empty().m_handle) {
368 m_handle->value.string = copyit ? ddf_strdup(val) : val;
369 if (!m_handle->value.string && val && *val)
371 m_handle->type=(safe ? ddf_body_t::DDF_STRING : ddf_body_t::DDF_STRING_UNSAFE);
376 DDF& DDF::string(const char* val)
378 return string(const_cast<char*>(val), true);
381 DDF& DDF::unsafe_string(const char* val)
383 return string(const_cast<char*>(val), true, false);
386 DDF& DDF::string(long val)
390 sprintf(buf,"%ld",val);
394 DDF& DDF::string(double val)
398 snprintf(buf,39,"%f",val);
402 DDF& DDF::integer(long val)
404 if (empty().m_handle) {
405 m_handle->value.integer=val;
406 m_handle->type=ddf_body_t::DDF_INT;
411 DDF& DDF::integer(const char* val)
413 if (empty().m_handle) {
414 m_handle->value.integer=(val ? atol(val) : 0);
415 m_handle->type=ddf_body_t::DDF_INT;
420 DDF& DDF::floating(double val)
422 if (empty().m_handle) {
423 m_handle->value.floating=val;
424 m_handle->type=ddf_body_t::DDF_FLOAT;
429 DDF& DDF::floating(const char* val)
431 if (empty().m_handle) {
432 m_handle->value.floating=(val ? atof(val) : 0);
433 m_handle->type=ddf_body_t::DDF_FLOAT;
438 DDF& DDF::structure()
440 if (empty().m_handle) {
441 m_handle->type=ddf_body_t::DDF_STRUCT;
442 m_handle->value.children.first=nullptr;
443 m_handle->value.children.last=nullptr;
444 m_handle->value.children.current=nullptr;
445 m_handle->value.children.count=0;
452 if (empty().m_handle) {
453 m_handle->type=ddf_body_t::DDF_LIST;
454 m_handle->value.children.first=nullptr;
455 m_handle->value.children.last=nullptr;
456 m_handle->value.children.current=nullptr;
457 m_handle->value.children.count=0;
462 DDF& DDF::pointer(void* val)
464 if (empty().m_handle) {
465 m_handle->value.pointer=val;
466 m_handle->type=ddf_body_t::DDF_POINTER;
471 DDF& DDF::add(DDF& child)
473 if ((!isstruct() && !islist()) || !child.m_handle)
476 if (m_handle==child.m_handle->parent)
482 getmember(child.name()).destroy();
486 if (!m_handle->value.children.first)
487 m_handle->value.children.first=child.m_handle;
489 m_handle->value.children.last->next=child.m_handle;
490 child.m_handle->prev=m_handle->value.children.last;
492 m_handle->value.children.last=child.m_handle;
493 child.m_handle->parent=m_handle;
494 m_handle->value.children.count++;
498 DDF& DDF::addbefore(DDF& child, DDF& before)
500 if (!islist() || !child.m_handle || !before.m_handle || before.m_handle->parent!=m_handle)
504 if (m_handle->value.children.first==before.m_handle)
505 m_handle->value.children.first=child.m_handle;
506 child.m_handle->prev=before.m_handle->prev;
507 if (child.m_handle->prev)
508 child.m_handle->prev->next=child.m_handle;
509 before.m_handle->prev=child.m_handle;
510 child.m_handle->next=before.m_handle;
511 child.m_handle->parent=m_handle;
512 m_handle->value.children.count++;
516 DDF& DDF::addafter(DDF& child, DDF& after)
518 if (!islist() || !child.m_handle || !after.m_handle || after.m_handle->parent!=m_handle)
522 if (m_handle->value.children.last==after.m_handle)
523 m_handle->value.children.last=child.m_handle;
524 child.m_handle->next=after.m_handle->next;
525 if (child.m_handle->next)
526 child.m_handle->next->prev=child.m_handle;
527 after.m_handle->next=child.m_handle;
528 child.m_handle->prev=after.m_handle;
529 child.m_handle->parent=m_handle;
530 m_handle->value.children.count++;
534 void DDF::swap(DDF& arg)
536 ddf_body_t* temp=arg.m_handle;
537 arg.m_handle=m_handle;
543 if (!m_handle || !m_handle->parent)
547 m_handle->next->prev=m_handle->prev;
550 m_handle->prev->next=m_handle->next;
552 if (m_handle->parent->value.children.first==m_handle)
553 m_handle->parent->value.children.first=m_handle->next;
555 if (m_handle->parent->value.children.last==m_handle)
556 m_handle->parent->value.children.last=m_handle->prev;
558 if (m_handle->parent->value.children.current==m_handle)
559 m_handle->parent->value.children.current=m_handle->prev;
561 m_handle->parent->value.children.count--;
562 m_handle->parent=nullptr;
563 m_handle->next=nullptr;
564 m_handle->prev=nullptr;
568 DDF DDF::parent() const
572 p.m_handle=(m_handle ? m_handle->parent : nullptr);
580 if (islist() || isstruct())
581 f.m_handle=m_handle->value.children.current=m_handle->value.children.first;
589 if ((islist() || isstruct()) && m_handle->value.children.current!=m_handle->value.children.last) {
590 if (!m_handle->value.children.current)
591 n.m_handle=m_handle->value.children.current=m_handle->value.children.first;
593 n.m_handle=m_handle->value.children.current=m_handle->value.children.current->next;
602 if ((islist() || isstruct()) && m_handle->value.children.last) {
603 m_handle->value.children.current=m_handle->value.children.last->prev;
604 l.m_handle=m_handle->value.children.last;
613 if (islist() || isstruct()) {
614 p.m_handle=m_handle->value.children.current;
616 m_handle->value.children.current=m_handle->value.children.current->prev;
621 DDF DDF::operator[](const char* path) const
623 return getmember(path);
626 DDF DDF::operator[](unsigned long index) const
630 if (islist() && index<m_handle->value.children.count) {
631 for (d.m_handle=m_handle->value.children.first; index; index--)
632 d.m_handle=d.m_handle->next;
635 throw range_error("DDF object not a list with >=index+1 elements");
639 DDF DDF::addmember(const char* path)
641 char name[MAX_NAME_LEN+1];
642 const char* path_ptr=path;
644 if (m_handle && ddf_strlen(ddf_token(&path_ptr,name))>0) {
648 DDF new_member=getmember(name);
649 if (!new_member.m_handle) {
651 new_member=add(temp);
654 if (new_member.m_handle) {
655 if (ddf_strlen(path_ptr)>0) {
656 DDF last_member=new_member.addmember(path_ptr);
657 if (!last_member.m_handle)
658 return new_member.destroy();
669 DDF DDF::getmember(const char* path) const
672 char name[MAX_NAME_LEN+1];
673 const char* path_ptr=path;
675 ddf_token(&path_ptr, name);
678 else if (*name == '[') {
679 unsigned long i = strtoul(name+1, nullptr, 10);
680 if (islist() && i < m_handle->value.children.count)
681 current=operator[](i);
685 else if (isstruct()) {
686 current.m_handle = m_handle->value.children.first;
687 while (current.m_handle && strcmp(current.m_handle->name,name) != 0)
688 current.m_handle = current.m_handle->next;
691 current.m_handle = m_handle->value.children.first;
692 return current.getmember(path);
695 if (current.m_handle && path_ptr && *path_ptr)
696 current = current.getmember(path_ptr);
701 void ddf_print_indent(FILE* f, int indent)
703 for (; indent>0; indent--)
707 void DDF::dump(FILE* f, int indent) const
712 ddf_print_indent(f,indent);
714 switch (m_handle->type) {
716 case ddf_body_t::DDF_EMPTY:
719 fprintf(f," %s",m_handle->name);
722 case ddf_body_t::DDF_STRING:
723 case ddf_body_t::DDF_STRING_UNSAFE:
725 fprintf(f,"char* %s = ",m_handle->name);
727 fprintf(f,"char* = ");
728 if (const char* chptr=m_handle->value.string) {
735 fprintf(f,"nullptr");
738 case ddf_body_t::DDF_INT:
740 fprintf(f,"long %s = ",m_handle->name);
742 fprintf(f,"long = ");
743 fprintf(f,"%ld",m_handle->value.integer);
746 case ddf_body_t::DDF_FLOAT:
748 fprintf(f,"double %s = ",m_handle->name);
750 fprintf(f,"double = ");
751 fprintf(f,"%.15f",m_handle->value.floating);
754 case ddf_body_t::DDF_STRUCT:
755 fprintf(f,"struct ");
757 fprintf(f,"%s ",m_handle->name);
759 if (m_handle->value.children.count) {
762 child.m_handle=m_handle->value.children.first;
763 while (child.m_handle) {
764 child.dump(f,indent+2);
765 child.m_handle=child.m_handle->next;
768 ddf_print_indent(f,indent);
772 case ddf_body_t::DDF_LIST:
775 fprintf(f," %s",m_handle->name);
776 fprintf(f,"[%lu] {",m_handle->value.children.count);
777 if (m_handle->value.children.count) {
780 child.m_handle=m_handle->value.children.first;
781 while (child.m_handle) {
782 child.dump(f,indent+2);
783 child.m_handle=child.m_handle->next;
786 ddf_print_indent(f,indent);
790 case ddf_body_t::DDF_POINTER:
792 fprintf(f,"void* %s = ",m_handle->name);
794 fprintf(f,"void* = ");
795 if (m_handle->value.pointer)
796 fprintf(f,"%p",m_handle->value.pointer);
798 fprintf(f,"nullptr");
802 fprintf(f,"UNKNOWN -- WARNING: ILLEGAL VALUE");
806 fprintf(f,"nullptr");
810 // Serialization is fairly easy. We have to walk the DDF and hand-generate a
811 // wddxPacket XML fragment, with some simple extensions. We escape the four major
812 // special characters, which requires that we output strings one char at a time.
814 void xml_encode(ostream& os, const char* start)
817 while (start && *start) {
818 pos = strcspn(start, "\"<>&");
825 case '"': os << """; break;
826 case '<': os << "<"; break;
827 case '>': os << ">"; break;
828 case '&': os << "&"; break;
829 default: os << *start;
836 void serialize(ddf_body_t* p, ostream& os, bool name_attr=true)
841 case ddf_body_t::DDF_STRING:
842 case ddf_body_t::DDF_STRING_UNSAFE:
844 if (name_attr && p->name) {
846 xml_encode(os,p->name);
849 if (p->value.string) {
850 if (p->type == ddf_body_t::DDF_STRING) {
852 xml_encode(os,p->value.string);
855 os << " unsafe=\"1\">";
856 xml_encode(os,XMLToolingConfig::getConfig().getURLEncoder()->encode(p->value.string).c_str());
864 case ddf_body_t::DDF_INT:
866 if (name_attr && p->name) {
868 xml_encode(os,p->name);
871 os << '>' << p->value.integer << "</number>";
874 case ddf_body_t::DDF_FLOAT:
876 if (name_attr && p->name) {
878 xml_encode(os,p->name);
881 os << '>' << fixed << p->value.floating << dec << "</number>";
884 case ddf_body_t::DDF_STRUCT:
887 if (name_attr && p->name) {
889 xml_encode(os,p->name);
893 ddf_body_t* child=p->value.children.first;
895 os << "<var name=\"";
896 xml_encode(os,child->name);
898 serialize(child,os,false);
906 case ddf_body_t::DDF_LIST:
908 os << "<array length=\"" << p->value.children.count << '"';
909 if (name_attr && p->name) {
911 xml_encode(os,p->name);
915 ddf_body_t* child=p->value.children.first;
924 case ddf_body_t::DDF_EMPTY:
925 case ddf_body_t::DDF_POINTER:
928 if (name_attr && p->name) {
930 xml_encode(os,p->name);
941 // The stream insertion will work for any ostream-based object.
943 SHIBSP_API ostream& shibsp::operator<<(ostream& os, const DDF& obj)
946 os << "<wddxPacket version=\"1.0\" lowercase=\"no\"><header/><data>";
947 serialize(obj.m_handle,os);
948 os << "</data></wddxPacket>";
952 // This is a DTD internal subset based on a compatible permutation of the WDDX spec, with the
953 // extension of a name attribute on all the typed elements, which DDF has, but WDDX does not.
956 static const char* g_DocType=
958 <!DOCTYPE wddxPacket [\n\
959 <!ELEMENT wddxPacket (header, data)>\n\
960 <!ATTLIST wddxPacket version CDATA #FIXED \"1.0\" lowercase (yes|no) \"yes\">\n\
961 <!ELEMENT header (comment?)>\n\
962 <!ELEMENT comment (#PCDATA)>\n\
963 <!ELEMENT data (null | number | string | array | struct)>\n\
964 <!ELEMENT null EMPTY>\n\
965 <!ATTLIST null name CDATA #IMPLIED type CDATA #IMPLIED>\n\
966 <!ELEMENT string (#PCDATA | char)*>\n\
967 <!ATTLIST string name CDATA #IMPLIED type CDATA #IMPLIED>\n\
968 <!ELEMENT char EMPTY>\n\
969 <!ATTLIST char code CDATA #REQUIRED>\n\
970 <!ELEMENT number (#PCDATA)>\n\
971 <!ATTLIST number name CDATA #IMPLIED type CDATA #IMPLIED>\n\
972 <!ELEMENT array (null | number | string | array | struct)*>\n\
973 <!ATTLIST array length CDATA #REQUIRED name CDATA #IMPLIED type CDATA #IMPLIED>\n\
974 <!ELEMENT struct (var*)>\n\
975 <!ATTLIST struct name CDATA #IMPLIED type CDATA #IMPLIED>\n\
976 <!ELEMENT var (null | number | string | array | struct)>\n\
977 <!ATTLIST var name CDATA #REQUIRED>\n\
981 // This function constructs a DDF object equivalent to the wddx data element rooted
984 static const XMLCh _no[] = UNICODE_LITERAL_2(n,o);
985 static const XMLCh _name[] = UNICODE_LITERAL_4(n,a,m,e);
986 static const XMLCh _var[] = UNICODE_LITERAL_3(v,a,r);
987 static const XMLCh _string[] = UNICODE_LITERAL_6(s,t,r,i,n,g);
988 static const XMLCh _number[] = UNICODE_LITERAL_6(n,u,m,b,e,r);
989 static const XMLCh _array[] = UNICODE_LITERAL_5(a,r,r,a,y);
990 static const XMLCh _struct[] = UNICODE_LITERAL_6(s,t,r,u,c,t);
991 static const XMLCh _lowercase[] = UNICODE_LITERAL_9(l,o,w,e,r,c,a,s,e);
992 static const XMLCh _unsafe[] = UNICODE_LITERAL_6(u,n,s,a,f,e);
994 DDF deserialize(DOMElement* root, bool lowercase)
997 auto_ptr_char name_val(root->getAttributeNS(nullptr, _name));
998 if (name_val.get() && *name_val.get()) {
1000 for (char* pch=const_cast<char*>(name_val.get()); *pch=tolower(*pch); pch++);
1001 obj.name(name_val.get());
1004 const XMLCh* tag=root->getTagName();
1005 if (XMLString::equals(tag,_var)) {
1006 root=XMLHelper::getFirstChildElement(root);
1007 tag=(root ? root->getTagName() : &chNull);
1010 if (XMLString::equals(tag,_string)) {
1011 DOMNode* child=root->getFirstChild();
1012 if (child && child->getNodeType()==DOMNode::TEXT_NODE) {
1013 const XMLCh* unsafe = root->getAttributeNS(nullptr, _unsafe);
1014 if (unsafe && *unsafe==chDigit_1) {
1015 // If it's unsafe, it's not UTF-8 data, so we have to convert to ASCII and decode it.
1016 char* encoded = XMLString::transcode(child->getNodeValue());
1017 XMLToolingConfig::getConfig().getURLEncoder()->decode(encoded);
1018 obj.string(encoded, true, false); // re-copy into free-able buffer, plus mark unsafe
1019 XMLString::release(&encoded);
1022 char* val = toUTF8(child->getNodeValue(), true); // use malloc
1023 obj.string(val, false); // don't re-copy the string
1027 else if (XMLString::equals(tag,_number)) {
1028 DOMNode* child=root->getFirstChild();
1029 if (child && child->getNodeType()==DOMNode::TEXT_NODE) {
1030 auto_ptr_char val(child->getNodeValue());
1031 if (val.get() && strchr(val.get(),'.'))
1032 obj.floating(val.get());
1034 obj.integer(val.get());
1037 else if (XMLString::equals(tag,_array)) {
1039 DOMNodeList* children=root->getChildNodes();
1040 for (unsigned int i=0; children && i<children->getLength(); i++)
1041 if (children->item(i)->getNodeType()==DOMNode::ELEMENT_NODE) {
1042 DDF temp=deserialize(static_cast<DOMElement*>(children->item(i)),lowercase);
1046 else if (XMLString::equals(tag,_struct)) {
1048 DOMNodeList* children=root->getChildNodes();
1049 for (unsigned int i=0; children && i<children->getLength(); i++)
1050 if (children->item(i)->getNodeType()==DOMNode::ELEMENT_NODE) {
1051 DDF temp=deserialize(static_cast<DOMElement*>(children->item(i)),lowercase);
1059 SHIBSP_API istream& shibsp::operator>>(istream& is, DDF& obj)
1061 // Parse the input stream into a DOM tree and construct the equivalent DDF.
1062 DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(is);
1063 XercesJanitor<DOMDocument> docj(doc);
1064 const XMLCh* lowercase=doc->getDocumentElement()->getAttribute(_lowercase);
1065 DOMElement* first=XMLHelper::getFirstChildElement(XMLHelper::getLastChildElement(doc->getDocumentElement()));
1067 obj=deserialize(first,XMLString::compareString(lowercase,_no)!=0);