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 * A helper class for working with W3C DOM objects.
28 #include "exceptions.h"
30 #include "XMLObject.h"
31 #include "util/XMLHelper.h"
32 #include "util/XMLConstants.h"
34 #include <xercesc/framework/MemBufFormatTarget.hpp>
35 #include <xercesc/util/XMLUniDefs.hpp>
37 using namespace xmltooling;
38 using namespace xercesc;
41 static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
43 bool XMLHelper::hasXSIType(const DOMElement* e)
45 return (e && e->hasAttributeNS(xmlconstants::XSI_NS, type));
48 xmltooling::QName* XMLHelper::getXSIType(const DOMElement* e)
50 DOMAttr* attribute = e->getAttributeNodeNS(xmlconstants::XSI_NS, type);
52 const XMLCh* attributeValue = attribute->getTextContent();
53 if (attributeValue && *attributeValue) {
55 if ((i=XMLString::indexOf(attributeValue,chColon))>0) {
56 XMLCh* prefix=new XMLCh[i+1];
57 XMLString::subString(prefix,attributeValue,0,i);
59 xmltooling::QName* ret=new xmltooling::QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix);
64 return new xmltooling::QName(e->lookupNamespaceURI(nullptr), attributeValue);
72 DOMAttr* XMLHelper::getIdAttribute(const DOMElement* domElement)
74 if(!domElement->hasAttributes()) {
78 DOMNamedNodeMap* attributes = domElement->getAttributes();
80 for(XMLSize_t i = 0; i < attributes->getLength(); i++) {
81 attribute = static_cast<DOMAttr*>(attributes->item(i));
82 if(attribute->isId()) {
90 const XMLObject* XMLHelper::getXMLObjectById(const XMLObject& tree, const XMLCh* id)
92 if (XMLString::equals(id, tree.getXMLID()))
96 const list<XMLObject*>& children = tree.getOrderedChildren();
97 for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i) {
99 ret = getXMLObjectById(*(*i), id);
108 XMLObject* XMLHelper::getXMLObjectById(XMLObject& tree, const XMLCh* id)
110 if (XMLString::equals(id, tree.getXMLID()))
114 const list<XMLObject*>& children = tree.getOrderedChildren();
115 for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i) {
117 ret = getXMLObjectById(*(*i), id);
126 void XMLHelper::getNonVisiblyUsedPrefixes(const XMLObject& tree, map<xstring,xstring>& prefixes)
128 map<xstring,xstring> child_prefixes;
129 const list<XMLObject*>& children = tree.getOrderedChildren();
130 for (list<XMLObject*>::const_iterator i = children.begin(); i != children.end(); ++i) {
132 getNonVisiblyUsedPrefixes(*(*i), child_prefixes);
134 const set<Namespace>& nsset = tree.getNamespaces();
135 for (set<Namespace>::const_iterator ns = nsset.begin(); ns != nsset.end(); ++ns) {
136 // Check for xmlns:xml.
137 if (XMLString::equals(ns->getNamespacePrefix(), xmlconstants::XML_PREFIX) && XMLString::equals(ns->getNamespaceURI(), xmlconstants::XML_NS))
139 switch (ns->usage()) {
140 case Namespace::Indeterminate:
142 case Namespace::VisiblyUsed:
144 // See if the prefix was noted as non-visible below.
145 const XMLCh* p = ns->getNamespacePrefix() ? ns->getNamespacePrefix() : &chNull;
146 map<xstring,xstring>::iterator decl = child_prefixes.find(p);
147 if (decl != child_prefixes.end()) {
148 // It's declared below, see if it's the same namespace. If so, pull it from the set,
149 // otherwise leave it in the set.
150 if (decl->second == (ns->getNamespaceURI() ? ns->getNamespaceURI() : &chNull))
151 child_prefixes.erase(decl);
155 case Namespace::NonVisiblyUsed:
156 // It may already be in the map from another branch of the tree, but as long
157 // as it's set to something so the parent knows about it, we're good.
158 prefixes[ns->getNamespacePrefix() ? ns->getNamespacePrefix() : &chNull] = (ns->getNamespaceURI() ? ns->getNamespaceURI() : &chNull);
163 prefixes.insert(child_prefixes.begin(), child_prefixes.end());
166 xmltooling::QName* XMLHelper::getNodeQName(const DOMNode* domNode)
169 return new xmltooling::QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix());
173 xmltooling::QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute)
175 return getNodeValueAsQName(attribute);
178 xmltooling::QName* XMLHelper::getNodeValueAsQName(const DOMNode* domNode)
183 const XMLCh* value=domNode->getTextContent();
184 if (!value || !*value)
188 if ((i=XMLString::indexOf(value,chColon))>0) {
189 XMLCh* prefix=new XMLCh[i+1];
190 XMLString::subString(prefix,value,0,i);
192 xmltooling::QName* ret=new xmltooling::QName(domNode->lookupNamespaceURI(prefix), value + i + 1, prefix);
197 return new xmltooling::QName(domNode->lookupNamespaceURI(nullptr), value);
200 bool XMLHelper::getNodeValueAsBool(const xercesc::DOMNode* domNode, bool def)
204 const XMLCh* value = domNode->getNodeValue();
205 if (!value || !*value)
207 if (*value == chLatin_t || *value == chDigit_1)
209 else if (*value == chLatin_f || *value == chDigit_0)
214 DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* childElement)
216 DOMDocument* parentDocument = parentElement->getOwnerDocument();
217 if (childElement->getOwnerDocument() != parentDocument) {
218 childElement = static_cast<DOMElement*>(parentDocument->importNode(childElement, true));
221 parentElement->appendChild(childElement);
225 bool XMLHelper::isNodeNamed(const xercesc::DOMNode* n, const XMLCh* ns, const XMLCh* local)
227 return (n && XMLString::equals(local,n->getLocalName()) && XMLString::equals(ns,n->getNamespaceURI()));
230 const XMLCh* XMLHelper::getTextContent(const DOMElement* e)
232 DOMNode* child = e ? e->getFirstChild() : nullptr;
234 if (child->getNodeType() == DOMNode::TEXT_NODE)
235 return child->getNodeValue();
236 child = child->getNextSibling();
241 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* localName)
243 DOMNode* child = n ? n->getFirstChild() : nullptr;
244 while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
245 child = child->getNextSibling();
246 if (child && localName) {
247 if (!XMLString::equals(localName,child->getLocalName()))
248 return getNextSiblingElement(child, localName);
250 return static_cast<DOMElement*>(child);
253 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* localName)
255 DOMNode* child = n ? n->getLastChild() : nullptr;
256 while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)
257 child = child->getPreviousSibling();
258 if (child && localName) {
259 if (!XMLString::equals(localName,child->getLocalName()))
260 return getPreviousSiblingElement(child, localName);
262 return static_cast<DOMElement*>(child);
265 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
267 DOMElement* e = getFirstChildElement(n, localName);
268 while (e && !XMLString::equals(e->getNamespaceURI(),ns))
269 e = getNextSiblingElement(e, localName);
273 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
275 DOMElement* e = getLastChildElement(n, localName);
276 while (e && !XMLString::equals(e->getNamespaceURI(),ns))
277 e = getPreviousSiblingElement(e, localName);
281 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* localName)
283 DOMNode* sib = n ? n->getNextSibling() : nullptr;
284 while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
285 sib = sib->getNextSibling();
286 if (sib && localName) {
287 if (!XMLString::equals(localName,sib->getLocalName()))
288 return getNextSiblingElement(sib, localName);
290 return static_cast<DOMElement*>(sib);
293 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName)
295 DOMNode* sib = n ? n->getPreviousSibling() : nullptr;
296 while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)
297 sib = sib->getPreviousSibling();
298 if (sib && localName) {
299 if (!XMLString::equals(localName,sib->getLocalName()))
300 return getPreviousSiblingElement(sib, localName);
302 return static_cast<DOMElement*>(sib);
305 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
307 DOMElement* e = getNextSiblingElement(n, localName);
308 while (e && !XMLString::equals(e->getNamespaceURI(),ns))
309 e = getNextSiblingElement(e, localName);
313 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)
315 DOMElement* e = getPreviousSiblingElement(n, localName);
316 while (e && !XMLString::equals(e->getNamespaceURI(),ns))
317 e = getPreviousSiblingElement(e, localName);
321 string XMLHelper::getAttrString(const DOMElement* e, const char* defValue, const XMLCh* localName, const XMLCh* ns)
324 auto_ptr_char val(e->getAttributeNS(ns, localName));
325 if (val.get() && *val.get())
328 return defValue ? defValue : "";
331 int XMLHelper::getAttrInt(const DOMElement* e, int defValue, const XMLCh* localName, const XMLCh* ns)
334 const XMLCh* val = e->getAttributeNS(ns, localName);
336 int i = XMLString::parseInt(val);
344 bool XMLHelper::getAttrBool(const DOMElement* e, bool defValue, const XMLCh* localName, const XMLCh* ns)
347 const XMLCh* val = e->getAttributeNS(ns, localName);
349 if (*val == chLatin_t || *val == chDigit_1)
351 if (*val == chLatin_f || *val == chDigit_0)
358 void XMLHelper::serialize(const DOMNode* n, std::string& buf, bool pretty)
360 static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
361 static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull };
363 MemBufFormatTarget target;
364 DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
366 #ifdef XMLTOOLING_XERCESC_COMPLIANT_DOMLS
367 DOMLSSerializer* serializer = static_cast<DOMImplementationLS*>(impl)->createLSSerializer();
368 XercesJanitor<DOMLSSerializer> janitor(serializer);
369 if (pretty && serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty))
370 serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty);
371 DOMLSOutput *theOutput = static_cast<DOMImplementationLS*>(impl)->createLSOutput();
372 XercesJanitor<DOMLSOutput> j_theOutput(theOutput);
373 theOutput->setEncoding(UTF8);
374 theOutput->setByteStream(&target);
375 if (!serializer->write(n, theOutput))
376 throw XMLParserException("unable to serialize XML");
378 DOMWriter* serializer = static_cast<DOMImplementationLS*>(impl)->createDOMWriter();
379 XercesJanitor<DOMWriter> janitor(serializer);
380 serializer->setEncoding(UTF8);
381 if (pretty && serializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty))
382 serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty);
383 if (!serializer->writeNode(&target, *n))
384 throw XMLParserException("unable to serialize XML");
388 buf.append(reinterpret_cast<const char*>(target.getRawBuffer()),target.getLen());
392 class StreamFormatTarget : public XMLFormatTarget
395 StreamFormatTarget(std::ostream& out) : m_out(out) {}
396 ~StreamFormatTarget() {}
398 void writeChars(const XMLByte *const toWrite, const xsecsize_t count, XMLFormatter *const formatter) {
399 m_out.write(reinterpret_cast<const char*>(toWrite),count);
411 ostream& XMLHelper::serialize(const DOMNode* n, ostream& out, bool pretty)
413 static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull };
414 static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull };
416 StreamFormatTarget target(out);
417 DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype);
419 #ifdef XMLTOOLING_XERCESC_COMPLIANT_DOMLS
420 DOMLSSerializer* serializer = static_cast<DOMImplementationLS*>(impl)->createLSSerializer();
421 XercesJanitor<DOMLSSerializer> janitor(serializer);
422 if (pretty && serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty))
423 serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty);
424 DOMLSOutput *theOutput = static_cast<DOMImplementationLS*>(impl)->createLSOutput();
425 XercesJanitor<DOMLSOutput> j_theOutput(theOutput);
426 theOutput->setEncoding(UTF8);
427 theOutput->setByteStream(&target);
428 if (!serializer->write(n, theOutput))
429 throw XMLParserException("unable to serialize XML");
431 DOMWriter* serializer=(static_cast<DOMImplementationLS*>(impl))->createDOMWriter();
432 XercesJanitor<DOMWriter> janitor(serializer);
433 serializer->setEncoding(UTF8);
434 if (pretty && serializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty))
435 serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty);
436 if (!serializer->writeNode(&target,*n))
437 throw XMLParserException("unable to serialize XML");
443 ostream& xmltooling::operator<<(ostream& ostr, const DOMNode& node)
445 return XMLHelper::serialize(&node, ostr);
448 ostream& xmltooling::operator<<(ostream& ostr, const XMLObject& obj)
450 return ostr << *(obj.marshall());