X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-xmltooling.git;a=blobdiff_plain;f=xmltooling%2Futil%2FXMLHelper.cpp;h=26823958c5d9d4dce3fb3583828f4ba52f3162fd;hp=7a68ef460ff900b170d8406670318de88ae8e4f5;hb=2d795c731e6729309044607154978696a87fd900;hpb=65b795f1068218ffddebac9aa254ca4456ede47d diff --git a/xmltooling/util/XMLHelper.cpp b/xmltooling/util/XMLHelper.cpp index 7a68ef4..2682395 100644 --- a/xmltooling/util/XMLHelper.cpp +++ b/xmltooling/util/XMLHelper.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the + * License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. */ /** @@ -22,29 +26,31 @@ #include "internal.h" #include "exceptions.h" +#include "QName.h" +#include "XMLObject.h" #include "util/XMLHelper.h" #include "util/XMLConstants.h" +#include +#include +#include #include #include using namespace xmltooling; +using namespace xercesc; +using namespace boost::lambda; +using namespace boost; using namespace std; static const XMLCh type[]={chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull }; bool XMLHelper::hasXSIType(const DOMElement* e) { - if (e) { - if (e->hasAttributeNS(xmlconstants::XSI_NS, type)) { - return true; - } - } - - return false; + return (e && e->hasAttributeNS(xmlconstants::XSI_NS, type)); } -QName* XMLHelper::getXSIType(const DOMElement* e) +xmltooling::QName* XMLHelper::getXSIType(const DOMElement* e) { DOMAttr* attribute = e->getAttributeNodeNS(xmlconstants::XSI_NS, type); if (attribute) { @@ -55,35 +61,35 @@ QName* XMLHelper::getXSIType(const DOMElement* e) XMLCh* prefix=new XMLCh[i+1]; XMLString::subString(prefix,attributeValue,0,i); prefix[i]=chNull; - QName* ret=new QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix); + xmltooling::QName* ret=new xmltooling::QName(e->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix); delete[] prefix; return ret; } else { - return new QName(e->lookupNamespaceURI(NULL), attributeValue); + return new xmltooling::QName(e->lookupNamespaceURI(nullptr), attributeValue); } } } - return NULL; + return nullptr; } DOMAttr* XMLHelper::getIdAttribute(const DOMElement* domElement) { if(!domElement->hasAttributes()) { - return NULL; + return nullptr; } DOMNamedNodeMap* attributes = domElement->getAttributes(); DOMAttr* attribute; - for(XMLSize_t i = 0; i < attributes->getLength(); i++) { + for(XMLSize_t i = 0; i < attributes->getLength(); ++i) { attribute = static_cast(attributes->item(i)); if(attribute->isId()) { return attribute; } } - return NULL; + return nullptr; } const XMLObject* XMLHelper::getXMLObjectById(const XMLObject& tree, const XMLCh* id) @@ -93,7 +99,7 @@ const XMLObject* XMLHelper::getXMLObjectById(const XMLObject& tree, const XMLCh* const XMLObject* ret; const list& children = tree.getOrderedChildren(); - for (list::const_iterator i=children.begin(); i!=children.end(); ++i) { + for (list::const_iterator i = children.begin(); i != children.end(); ++i) { if (*i) { ret = getXMLObjectById(*(*i), id); if (ret) @@ -101,17 +107,17 @@ const XMLObject* XMLHelper::getXMLObjectById(const XMLObject& tree, const XMLCh* } } - return NULL; + return nullptr; } XMLObject* XMLHelper::getXMLObjectById(XMLObject& tree, const XMLCh* id) { if (XMLString::equals(id, tree.getXMLID())) return &tree; - + XMLObject* ret; const list& children = tree.getOrderedChildren(); - for (list::const_iterator i=children.begin(); i!=children.end(); ++i) { + for (list::const_iterator i = children.begin(); i != children.end(); ++i) { if (*i) { ret = getXMLObjectById(*(*i), id); if (ret) @@ -119,33 +125,95 @@ XMLObject* XMLHelper::getXMLObjectById(XMLObject& tree, const XMLCh* id) } } - return NULL; + return nullptr; } -QName* XMLHelper::getNodeQName(const DOMNode* domNode) +void XMLHelper::getNonVisiblyUsedPrefixes(const XMLObject& tree, map& prefixes) +{ + map child_prefixes; + for(list::const_iterator i = tree.getOrderedChildren().begin(); i != tree.getOrderedChildren().end(); ++i) { + if (*i) { + getNonVisiblyUsedPrefixes(*(*i), child_prefixes); + } + } + const set& nsset = tree.getNamespaces(); + for (set::const_iterator ns = nsset.begin(); ns != nsset.end(); ++ns) { + // Check for xmlns:xml. + if (XMLString::equals(ns->getNamespacePrefix(), xmlconstants::XML_PREFIX) && XMLString::equals(ns->getNamespaceURI(), xmlconstants::XML_NS)) + continue; + switch (ns->usage()) { + case Namespace::Indeterminate: + break; + case Namespace::VisiblyUsed: + { + // See if the prefix was noted as non-visible below. + const XMLCh* p = ns->getNamespacePrefix() ? ns->getNamespacePrefix() : &chNull; + map::iterator decl = child_prefixes.find(p); + if (decl != child_prefixes.end()) { + // It's declared below, see if it's the same namespace. If so, pull it from the set, + // otherwise leave it in the set. + if (decl->second == (ns->getNamespaceURI() ? ns->getNamespaceURI() : &chNull)) + child_prefixes.erase(decl); + } + break; + } + case Namespace::NonVisiblyUsed: + // It may already be in the map from another branch of the tree, but as long + // as it's set to something so the parent knows about it, we're good. + prefixes[ns->getNamespacePrefix() ? ns->getNamespacePrefix() : &chNull] = (ns->getNamespaceURI() ? ns->getNamespaceURI() : &chNull); + break; + } + } + + prefixes.insert(child_prefixes.begin(), child_prefixes.end()); +} + +xmltooling::QName* XMLHelper::getNodeQName(const DOMNode* domNode) { if (domNode) - return new QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix()); - return NULL; + return new xmltooling::QName(domNode->getNamespaceURI(), domNode->getLocalName(), domNode->getPrefix()); + return nullptr; +} + +xmltooling::QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute) +{ + return getNodeValueAsQName(attribute); } -QName* XMLHelper::getAttributeValueAsQName(const DOMAttr* attribute) +xmltooling::QName* XMLHelper::getNodeValueAsQName(const DOMNode* domNode) { - if (!attribute) - return NULL; + if (!domNode) + return nullptr; + const XMLCh* value=domNode->getTextContent(); + if (!value || !*value) + return nullptr; + int i; - const XMLCh* attributeValue=attribute->getTextContent(); - if (attributeValue && (i=XMLString::indexOf(attributeValue,chColon))>0) { + if ((i=XMLString::indexOf(value,chColon))>0) { XMLCh* prefix=new XMLCh[i+1]; - XMLString::subString(prefix,attributeValue,0,i); + XMLString::subString(prefix,value,0,i); prefix[i]=chNull; - QName* ret=new QName(attribute->lookupNamespaceURI(prefix), attributeValue + i + 1, prefix); + xmltooling::QName* ret=new xmltooling::QName(domNode->lookupNamespaceURI(prefix), value + i + 1, prefix); delete[] prefix; return ret; } - return new QName(attribute->lookupNamespaceURI(NULL), attributeValue); + return new xmltooling::QName(domNode->lookupNamespaceURI(nullptr), value); +} + +bool XMLHelper::getNodeValueAsBool(const xercesc::DOMNode* domNode, bool def) +{ + if (!domNode) + return def; + const XMLCh* value = domNode->getNodeValue(); + if (!value || !*value) + return def; + if (*value == chLatin_t || *value == chDigit_1) + return true; + else if (*value == chLatin_f || *value == chDigit_0) + return false; + return def; } DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* childElement) @@ -159,20 +227,25 @@ DOMElement* XMLHelper::appendChildElement(DOMElement* parentElement, DOMElement* return childElement; } +bool XMLHelper::isNodeNamed(const xercesc::DOMNode* n, const XMLCh* ns, const XMLCh* local) +{ + return (n && XMLString::equals(local,n->getLocalName()) && XMLString::equals(ns,n->getNamespaceURI())); +} + const XMLCh* XMLHelper::getTextContent(const DOMElement* e) { - DOMNode* child=e->getFirstChild(); + DOMNode* child = e ? e->getFirstChild() : nullptr; while (child) { - if (child->getNodeType()==DOMNode::TEXT_NODE) + if (child->getNodeType() == DOMNode::TEXT_NODE) return child->getNodeValue(); - child=child->getNextSibling(); + child = child->getNextSibling(); } - return NULL; + return nullptr; } DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* localName) { - DOMNode* child = n->getFirstChild(); + DOMNode* child = n ? n->getFirstChild() : nullptr; while (child && child->getNodeType() != DOMNode::ELEMENT_NODE) child = child->getNextSibling(); if (child && localName) { @@ -184,7 +257,7 @@ DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* local DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* localName) { - DOMNode* child = n->getLastChild(); + DOMNode* child = n ? n->getLastChild() : nullptr; while (child && child->getNodeType() != DOMNode::ELEMENT_NODE) child = child->getPreviousSibling(); if (child && localName) { @@ -212,7 +285,7 @@ DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, co DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* localName) { - DOMNode* sib = n->getNextSibling(); + DOMNode* sib = n ? n->getNextSibling() : nullptr; while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE) sib = sib->getNextSibling(); if (sib && localName) { @@ -224,7 +297,7 @@ DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* loca DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName) { - DOMNode* sib = n->getPreviousSibling(); + DOMNode* sib = n ? n->getPreviousSibling() : nullptr; while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE) sib = sib->getPreviousSibling(); if (sib && localName) { @@ -250,19 +323,74 @@ DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* return e; } +string XMLHelper::getAttrString(const DOMElement* e, const char* defValue, const XMLCh* localName, const XMLCh* ns) +{ + if (e) { + auto_ptr_char val(e->getAttributeNS(ns, localName)); + if (val.get() && *val.get()) + return val.get(); + } + return defValue ? defValue : ""; +} + +int XMLHelper::getAttrInt(const DOMElement* e, int defValue, const XMLCh* localName, const XMLCh* ns) +{ + if (e) { + const XMLCh* val = e->getAttributeNS(ns, localName); + if (val && *val) { + try { + return XMLString::parseInt(val); + } + catch (XMLException&) { + } + } + } + return defValue; +} + +bool XMLHelper::getAttrBool(const DOMElement* e, bool defValue, const XMLCh* localName, const XMLCh* ns) +{ + if (e) { + const XMLCh* val = e->getAttributeNS(ns, localName); + if (val) { + if (*val == chLatin_t || *val == chDigit_1) + return true; + if (*val == chLatin_f || *val == chDigit_0) + return false; + } + } + return defValue; +} + void XMLHelper::serialize(const DOMNode* n, std::string& buf, bool pretty) { static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull }; - static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull }; + static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull }; + + MemBufFormatTarget target; DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype); - DOMWriter* serializer=(static_cast(impl))->createDOMWriter(); + +#ifdef XMLTOOLING_XERCESC_COMPLIANT_DOMLS + DOMLSSerializer* serializer = static_cast(impl)->createLSSerializer(); + XercesJanitor janitor(serializer); + if (pretty && serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty)) + serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty); + DOMLSOutput *theOutput = static_cast(impl)->createLSOutput(); + XercesJanitor j_theOutput(theOutput); + theOutput->setEncoding(UTF8); + theOutput->setByteStream(&target); + if (!serializer->write(n, theOutput)) + throw XMLParserException("unable to serialize XML"); +#else + DOMWriter* serializer = static_cast(impl)->createDOMWriter(); XercesJanitor janitor(serializer); serializer->setEncoding(UTF8); if (pretty && serializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty)) serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty); - MemBufFormatTarget target; - if (!serializer->writeNode(&target,*n)) + if (!serializer->writeNode(&target, *n)) throw XMLParserException("unable to serialize XML"); +#endif + buf.erase(); buf.append(reinterpret_cast(target.getRawBuffer()),target.getLen()); } @@ -274,7 +402,7 @@ namespace { StreamFormatTarget(std::ostream& out) : m_out(out) {} ~StreamFormatTarget() {} - void writeChars(const XMLByte *const toWrite, const unsigned int count, XMLFormatter *const formatter) { + void writeChars(const XMLByte *const toWrite, const xsecsize_t count, XMLFormatter *const formatter) { m_out.write(reinterpret_cast(toWrite),count); } @@ -290,16 +418,32 @@ namespace { ostream& XMLHelper::serialize(const DOMNode* n, ostream& out, bool pretty) { static const XMLCh impltype[] = { chLatin_L, chLatin_S, chNull }; - static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDigit_8, chNull }; + static const XMLCh UTF8[]={ chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull }; + + StreamFormatTarget target(out); DOMImplementation* impl=DOMImplementationRegistry::getDOMImplementation(impltype); + +#ifdef XMLTOOLING_XERCESC_COMPLIANT_DOMLS + DOMLSSerializer* serializer = static_cast(impl)->createLSSerializer(); + XercesJanitor janitor(serializer); + if (pretty && serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty)) + serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, pretty); + DOMLSOutput *theOutput = static_cast(impl)->createLSOutput(); + XercesJanitor j_theOutput(theOutput); + theOutput->setEncoding(UTF8); + theOutput->setByteStream(&target); + if (!serializer->write(n, theOutput)) + throw XMLParserException("unable to serialize XML"); +#else DOMWriter* serializer=(static_cast(impl))->createDOMWriter(); XercesJanitor janitor(serializer); serializer->setEncoding(UTF8); if (pretty && serializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty)) serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, pretty); - StreamFormatTarget target(out); if (!serializer->writeNode(&target,*n)) throw XMLParserException("unable to serialize XML"); +#endif + return out; } @@ -310,5 +454,11 @@ ostream& xmltooling::operator<<(ostream& ostr, const DOMNode& node) ostream& xmltooling::operator<<(ostream& ostr, const XMLObject& obj) { - return ostr << *(obj.marshall()); + try { + return ostr << *(obj.marshall()); + } + catch (DOMException& ex) { + auto_ptr_char msg(ex.getMessage()); + throw XMLParserException(msg.get()); + } }