Function to serialize to stream.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / XMLHelper.cpp
1 /*
2  *  Copyright 2001-2006 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * XMLHelper.cpp
19  * 
20  * A helper class for working with W3C DOM objects. 
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "util/XMLHelper.h"
26 #include "util/XMLConstants.h"
27
28 #include <xercesc/framework/MemBufFormatTarget.hpp>
29 #include <xercesc/util/XMLUniDefs.hpp>
30
31 using namespace xmltooling;
32
33 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
34     
35 bool XMLHelper::hasXSIType(const DOMElement* e)
36 {
37     if (e) {
38         if (e->hasAttributeNS(xmlconstants::XSI_NS, type)) {
39             return true;
40         }
41     }
42
43     return false;
44 }
45
46 QName* XMLHelper::getXSIType(const DOMElement* e)
47 {
48     DOMAttr* attribute = e->getAttributeNodeNS(xmlconstants::XSI_NS, type);
49     if (attribute) {
50         const XMLCh* attributeValue = attribute->getTextContent();
51         if (attributeValue && *attributeValue) {
52             int i;
53             if ((i=XMLString::indexOf(attributeValue,chColon))>0) {
54                 XMLCh* prefix=new XMLCh[i+1];
55                 XMLString::subString(prefix,attributeValue,0,i);
56                 prefix[i]=chNull;
57                 QName* ret=new QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);
58                 delete[] prefix;
59                 return ret;
60             }
61             else {
62                 return new QName(e->lookupNamespaceURI(&chNull), attributeValue);
63             }
64         }
65     }
66
67     return NULL;
68 }
69
70 DOMAttr* XMLHelper::getIdAttribute(const DOMElement* domElement)
71 {
72     if(!domElement->hasAttributes()) {
73         return NULL;
74     }
75     
76     DOMNamedNodeMap* attributes = domElement->getAttributes();
77     DOMAttr* attribute;
78     for(XMLSize_t i = 0; i < attributes->getLength(); i++) {
79         attribute = static_cast<DOMAttr*>(attributes->item(i));
80         if(attribute->isId()) {
81             return attribute;
82         }
83     }
84     
85     return NULL;
86 }
87
88 QName* XMLHelper::getNodeQName(const DOMNode* domNode)
89 {
90     if (domNode)
91         return new QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix());
92     return NULL; 
93 }
94
95 QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute)
96 {
97     if (!attribute)
98         return NULL;
99     
100     int i;
101     const XMLCh* attributeValue=attribute->getTextContent();
102     if (attributeValue && (i=XMLString::indexOf(attributeValue,chColon))>0) {
103         XMLCh* prefix=new XMLCh[i+1];
104         XMLString::subString(prefix,attributeValue,0,i);
105         prefix[i]=chNull;
106         QName* ret=new QName(attribute->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);
107         delete[] prefix;
108         return ret;
109     }
110     
111     return new QName(attribute->lookupNamespaceURI(NULL), attributeValue);
112 }
113
114 DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* childElement)
115 {
116     DOMDocument* parentDocument = parentElement->getOwnerDocument();
117     if (childElement->getOwnerDocument() != parentDocument) {
118         childElement = static_cast<DOMElement*>(parentDocument->importNode(childElement, true));
119     }
120
121     parentElement->appendChild(childElement);
122     return childElement;
123 }
124
125 const XMLCh* XMLHelper::getTextContent(const DOMElement* e)
126 {
127     DOMNode* child=e->getFirstChild();
128     while (child) {
129         if (child->getNodeType()==DOMNode::TEXT_NODE)
130             return child->getNodeValue();
131         child=child->getNextSibling();
132     }
133     return NULL;
134 }
135
136 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* localName)
137 {
138     DOMNode* child = n->getFirstChild();
139     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
140         child = child->getNextSibling();
141     if (child && localName) {
142         if (!XMLString::equals(localName,child->getLocalName()))
143             return getNextSiblingElement(child, localName);
144     }
145     return static_cast<DOMElement*>(child);
146 }    
147
148 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* localName)
149 {
150     DOMNode* child = n->getLastChild();
151     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
152         child = child->getPreviousSibling();
153     if (child && localName) {
154         if (!XMLString::equals(localName,child->getLocalName()))
155             return getPreviousSiblingElement(child, localName);
156     }
157     return static_cast<DOMElement*>(child);
158 }    
159
160 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
161 {
162     DOMElement* e = getFirstChildElement(n, localName);
163     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
164         e = getNextSiblingElement(e, localName);
165     return e;
166 }
167
168 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
169 {
170     DOMElement* e = getLastChildElement(n, localName);
171     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
172         e = getPreviousSiblingElement(e, localName);
173     return e;
174 }
175
176 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* localName)
177 {
178     DOMNode* sib = n->getNextSibling();
179     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
180         sib = sib->getNextSibling();
181     if (sib && localName) {
182         if (!XMLString::equals(localName,sib->getLocalName()))
183             return getNextSiblingElement(sib, localName);
184     }   
185     return static_cast<DOMElement*>(sib);
186 }
187
188 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName)
189 {
190     DOMNode* sib = n->getPreviousSibling();
191     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
192         sib = sib->getPreviousSibling();
193     if (sib && localName) {
194         if (!XMLString::equals(localName,sib->getLocalName()))
195             return getPreviousSiblingElement(sib, localName);
196     }   
197     return static_cast<DOMElement*>(sib);
198 }
199
200 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
201 {
202     DOMElement* e = getNextSiblingElement(n, localName);
203     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
204         e = getNextSiblingElement(e, localName);
205     return e;
206 }
207
208 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
209 {
210     DOMElement* e = getPreviousSiblingElement(n, localName);
211     while (e && !XMLString::equals(e->getNamespaceURI(),ns))
212         e = getPreviousSiblingElement(e, localName);
213     return e;
214 }
215
216 void XMLHelper::serialize(const DOMElement* e, std::string& buf)
217 {
218     static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
219     static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull };
220     DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
221     DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();
222     XercesJanitor<DOMWriter> janitor(serializer);
223     serializer->setEncoding(UTF8);
224     MemBufFormatTarget target;
225     if (!serializer->writeNode(&target,*e))
226         throw XMLParserException("unable to serialize XML");
227     buf.erase();
228     buf.append(reinterpret_cast<const char*>(target.getRawBuffer()),target.getLen());
229 }
230
231 namespace {
232     class StreamFormatTarget : public XMLFormatTarget
233     {
234     public:
235         StreamFormatTarget(std::ostream& out) : m_out(out) {}
236         ~StreamFormatTarget() {}
237
238         void writeChars(const XMLByte *const toWrite, const unsigned int count, XMLFormatter *const formatter) {
239             m_out.write(reinterpret_cast<const char*>(toWrite),count);
240         }
241
242         void flush() {
243             m_out.flush();
244         }
245
246     private:
247         std::ostream& m_out;
248     };
249 };
250
251 void XMLHelper::serialize(const DOMElement* e, std::ostream& out)
252 {
253     static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
254     static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull };
255     DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
256     DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();
257     XercesJanitor<DOMWriter> janitor(serializer);
258     serializer->setEncoding(UTF8);
259     StreamFormatTarget target(out);
260     if (!serializer->writeNode(&target,*e))
261         throw XMLParserException("unable to serialize XML");
262 }