| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.ibm.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| #include "DOMServices.hpp" |
| |
| |
| |
| #include <vector> |
| |
| |
| |
| #include <XalanDOM/XalanAttr.hpp> |
| #include <XalanDOM/XalanCDATASection.hpp> |
| #include <XalanDOM/XalanComment.hpp> |
| #include <XalanDOM/XalanDOMString.hpp> |
| #include <XalanDOM/XalanDocument.hpp> |
| #include <XalanDOM/XalanDocumentFragment.hpp> |
| #include <XalanDOM/XalanElement.hpp> |
| #include <XalanDOM/XalanNamedNodeMap.hpp> |
| #include <XalanDOM/XalanNodeList.hpp> |
| #include <XalanDOM/XalanProcessingInstruction.hpp> |
| #include <XalanDOM/XalanText.hpp> |
| |
| |
| |
| #include <PlatformSupport/DOMStringHelper.hpp> |
| #include <PlatformSupport/XalanUnicode.hpp> |
| |
| |
| |
| #include "DOMSupportException.hpp" |
| |
| |
| |
| // These XalanDOMString instances will hold the actual |
| // data. This way, the DOMSupport references can be const, |
| // but we can initialize the data when we want to. |
| static XalanDOMString s_XMLString; |
| static XalanDOMString s_XMLStringWithSeparator; |
| static XalanDOMString s_XMLNamespacePrefix; |
| static XalanDOMString s_XMLNamespaceURI; |
| static XalanDOMString s_XMLNamespace; |
| static XalanDOMString s_XMLNamespaceWithSeparator; |
| static XalanDOMString s_XMLNamespaceSeparatorString; |
| static XalanDOMString s_XMLNamespacePrefixURI; |
| |
| |
| |
| const XalanDOMString& DOMServices::s_XMLString = ::s_XMLString; |
| const XalanDOMString& DOMServices::s_XMLStringWithSeparator = ::s_XMLStringWithSeparator; |
| const XalanDOMString& DOMServices::s_XMLNamespacePrefix = ::s_XMLNamespacePrefix; |
| const XalanDOMString& DOMServices::s_XMLNamespaceURI = ::s_XMLNamespaceURI; |
| const XalanDOMString& DOMServices::s_XMLNamespace = ::s_XMLNamespace; |
| const XalanDOMString& DOMServices::s_XMLNamespaceWithSeparator = ::s_XMLNamespaceWithSeparator; |
| const XalanDOMString& DOMServices::s_XMLNamespaceSeparatorString = ::s_XMLNamespaceSeparatorString; |
| const XalanDOMString& DOMServices::s_XMLNamespacePrefixURI = ::s_XMLNamespacePrefixURI; |
| const XalanDOMString DOMServices::s_emptyString; |
| |
| |
| |
| // These four unsigned ints will hold the actual |
| // data. This way, the DOMSupport references can be const, |
| // but we can initialize the data when we want to. |
| static XalanDOMString::size_type s_XMLStringLength = 0; |
| static XalanDOMString::size_type s_XMLStringWithSeparatorLength = 0; |
| static XalanDOMString::size_type s_XMLNamespacePrefixLength = 0; |
| static XalanDOMString::size_type s_XMLNamespaceURILength = 0; |
| static XalanDOMString::size_type s_XMLNamespaceLength = 0; |
| static XalanDOMString::size_type s_XMLNamespaceWithSeparatorLength = 0; |
| static XalanDOMString::size_type s_XMLNamespaceSeparatorStringLength = 0; |
| static XalanDOMString::size_type s_XMLNamespacePrefixURILength = 0; |
| |
| |
| |
| const XalanDOMString::size_type& DOMServices::s_XMLStringLength = ::s_XMLStringLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLStringWithSeparatorLength = ::s_XMLStringWithSeparatorLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespacePrefixLength = ::s_XMLNamespacePrefixLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespaceURILength = ::s_XMLNamespaceURILength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespaceLength = ::s_XMLNamespaceLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespaceWithSeparatorLength = ::s_XMLNamespaceWithSeparatorLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespaceSeparatorStringLength = ::s_XMLNamespaceSeparatorStringLength; |
| const XalanDOMString::size_type& DOMServices::s_XMLNamespacePrefixURILength = ::s_XMLNamespacePrefixURILength; |
| |
| |
| DOMServices::WhitespaceSupport::WhitespaceSupport() |
| { |
| } |
| |
| |
| |
| DOMServices::WhitespaceSupport::~WhitespaceSupport() |
| { |
| } |
| |
| |
| |
| DOMServices::WhitespaceSupportDefault::WhitespaceSupportDefault() |
| { |
| } |
| |
| |
| |
| DOMServices::WhitespaceSupportDefault::~WhitespaceSupportDefault() |
| { |
| } |
| |
| |
| |
| bool |
| DOMServices::WhitespaceSupportDefault::isIgnorableWhitespace(const XalanText& node) const |
| { |
| const XalanDOMString theData(node.getData()); |
| |
| const XalanDOMString::size_type theLength = length(theData); |
| |
| XalanDOMString::size_type i = 0; |
| |
| for (; i < theLength; i++) |
| { |
| const XalanDOMChar theChar = charAt(theData, i); |
| |
| if (!isXMLWhitespace(theChar)) |
| { |
| break; |
| } |
| } |
| |
| return i == theLength ? true : false; |
| } |
| |
| |
| |
| void |
| DOMServices::initialize() |
| { |
| ::s_XMLString = XALAN_STATIC_UCODE_STRING("xml"); |
| ::s_XMLStringWithSeparator = XALAN_STATIC_UCODE_STRING("xml:"); |
| ::s_XMLNamespacePrefix = XALAN_STATIC_UCODE_STRING("xmlns:xml"); |
| ::s_XMLNamespaceURI = XALAN_STATIC_UCODE_STRING("http://www.w3.org/XML/1998/namespace"); |
| ::s_XMLNamespace = XALAN_STATIC_UCODE_STRING("xmlns"); |
| ::s_XMLNamespaceWithSeparator = XALAN_STATIC_UCODE_STRING("xmlns:"); |
| ::s_XMLNamespaceSeparatorString = XALAN_STATIC_UCODE_STRING(":"); |
| ::s_XMLNamespacePrefixURI = XALAN_STATIC_UCODE_STRING("http://www.w3.org/2000/xmlns/"); |
| |
| ::s_XMLStringLength = length(DOMServices::s_XMLString); |
| ::s_XMLStringWithSeparatorLength = length(DOMServices::s_XMLStringWithSeparator); |
| ::s_XMLNamespacePrefixLength = length(DOMServices::s_XMLNamespacePrefix); |
| ::s_XMLNamespaceURILength = length(DOMServices::s_XMLNamespaceURI); |
| ::s_XMLNamespaceLength = length(DOMServices::s_XMLNamespace); |
| ::s_XMLNamespaceWithSeparatorLength = length(DOMServices::s_XMLNamespaceWithSeparator); |
| ::s_XMLNamespaceSeparatorStringLength = length(DOMServices::s_XMLNamespaceSeparatorString); |
| ::s_XMLNamespacePrefixURILength = length(DOMServices::s_XMLNamespacePrefixURI); |
| } |
| |
| |
| |
| void |
| DOMServices::terminate() |
| { |
| releaseMemory(::s_XMLString); |
| releaseMemory(::s_XMLStringWithSeparator); |
| releaseMemory(::s_XMLNamespacePrefix); |
| releaseMemory(::s_XMLNamespaceURI); |
| releaseMemory(::s_XMLNamespace); |
| releaseMemory(::s_XMLNamespaceWithSeparator); |
| releaseMemory(::s_XMLNamespaceSeparatorString); |
| releaseMemory(::s_XMLNamespacePrefixURI); |
| |
| ::s_XMLStringLength = 0; |
| ::s_XMLStringWithSeparatorLength = 0; |
| ::s_XMLNamespacePrefixLength = 0; |
| ::s_XMLNamespaceURILength = 0; |
| ::s_XMLNamespaceLength = 0; |
| ::s_XMLNamespaceWithSeparatorLength = 0; |
| ::s_XMLNamespaceSeparatorStringLength = 0; |
| ::s_XMLNamespacePrefixURILength = 0; |
| } |
| |
| |
| |
| XalanDOMString |
| DOMServices::getNodeData(const XalanNode& node) |
| { |
| XalanDOMString data; |
| |
| getNodeData(node, data); |
| |
| return data; |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanNode& node, |
| XalanDOMString& data) |
| { |
| switch(node.getNodeType()) |
| { |
| case XalanNode::DOCUMENT_FRAGMENT_NODE: |
| { |
| const XalanDocumentFragment& theDocumentFragment = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanDocumentFragment&)node; |
| #else |
| static_cast<const XalanDocumentFragment&>(node); |
| #endif |
| getNodeData(theDocumentFragment, data); |
| } |
| break; |
| |
| case XalanNode::DOCUMENT_NODE: |
| { |
| const XalanDocument& theDocument = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanDocument&)node; |
| #else |
| static_cast<const XalanDocument&>(node); |
| #endif |
| getNodeData(theDocument, data); |
| } |
| break; |
| |
| case XalanNode::ELEMENT_NODE: |
| { |
| const XalanElement& theElement = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanElement&)node; |
| #else |
| static_cast<const XalanElement&>(node); |
| #endif |
| getNodeData(theElement, data); |
| } |
| break; |
| |
| case XalanNode::TEXT_NODE: |
| case XalanNode::CDATA_SECTION_NODE: |
| { |
| const XalanText& theTextNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanText&)node; |
| #else |
| static_cast<const XalanText&>(node); |
| #endif |
| |
| getNodeData(theTextNode, data); |
| } |
| break; |
| |
| case XalanNode::ATTRIBUTE_NODE: |
| { |
| const XalanAttr& theAttr = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanAttr&)node; |
| #else |
| static_cast<const XalanAttr&>(node); |
| #endif |
| getNodeData(theAttr, data); |
| } |
| break; |
| |
| case XalanNode::COMMENT_NODE: |
| { |
| const XalanComment& theComment = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanComment&)node; |
| #else |
| static_cast<const XalanComment&>(node); |
| #endif |
| getNodeData(theComment, data); |
| } |
| break; |
| |
| case XalanNode::PROCESSING_INSTRUCTION_NODE: |
| { |
| const XalanProcessingInstruction& thePI = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanProcessingInstruction&)node; |
| #else |
| static_cast<const XalanProcessingInstruction&>(node); |
| #endif |
| getNodeData(thePI, data); |
| } |
| break; |
| |
| default: |
| // ignore |
| break; |
| } |
| } |
| |
| |
| |
| XalanDOMString |
| DOMServices::getNodeData(const XalanDocument& document) |
| { |
| XalanDOMString data; |
| |
| getNodeData(document, data); |
| |
| return data; |
| } |
| |
| |
| |
| inline void |
| getChildData( |
| const XalanNode* child, |
| XalanDOMString& data) |
| { |
| const XalanNode::NodeType theType = child->getNodeType(); |
| |
| if (theType == XalanNode::ELEMENT_NODE) |
| { |
| const XalanElement* const theElementNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanElement*)child; |
| #else |
| static_cast<const XalanElement*>(child); |
| #endif |
| |
| DOMServices::getNodeData(*theElementNode, data); |
| } |
| else if (theType == XalanNode::TEXT_NODE || |
| theType == XalanNode::CDATA_SECTION_NODE) |
| { |
| const XalanText* theTextNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanText*)child; |
| #else |
| static_cast<const XalanText*>(child); |
| #endif |
| |
| DOMServices::getNodeData(*theTextNode, data); |
| } |
| } |
| |
| |
| |
| inline void |
| getChildrenData( |
| const XalanNode* firstChild, |
| XalanDOMString& data) |
| { |
| while(firstChild != 0) |
| { |
| getChildData(firstChild, data); |
| |
| firstChild = firstChild->getNextSibling(); |
| } |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanDocument& document, |
| XalanDOMString& data) |
| { |
| assert(document.getDocumentElement() != 0); |
| |
| getChildrenData(document.getDocumentElement(), data); |
| } |
| |
| |
| |
| XalanDOMString |
| DOMServices::getNodeData(const XalanDocumentFragment& documentFragment) |
| { |
| XalanDOMString data; |
| |
| getNodeData(documentFragment, data); |
| |
| return data; |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanDocumentFragment& documentFragment, |
| XalanDOMString& data) |
| { |
| const XalanNodeList* const nl = documentFragment.getChildNodes(); |
| assert(nl != 0); |
| |
| const unsigned int n = nl->getLength(); |
| |
| for(unsigned int i = 0; i < n; ++i) |
| { |
| const XalanNode* const child = nl->item(i); |
| assert(child != 0); |
| |
| getChildData(child, data); |
| } |
| } |
| |
| |
| |
| XalanDOMString |
| DOMServices::getNodeData(const XalanElement& element) |
| { |
| XalanDOMString data; |
| |
| getNodeData(element, data); |
| |
| return data; |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanElement& element, |
| XalanDOMString& data) |
| { |
| getChildrenData(element.getFirstChild(), data); |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanNode& node, |
| FormatterListener& formatterListener, |
| MemberFunctionPtr function) |
| { |
| switch(node.getNodeType()) |
| { |
| case XalanNode::DOCUMENT_FRAGMENT_NODE: |
| { |
| const XalanDocumentFragment& theDocumentFragment = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanDocumentFragment&)node; |
| #else |
| static_cast<const XalanDocumentFragment&>(node); |
| #endif |
| getNodeData(theDocumentFragment, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::DOCUMENT_NODE: |
| { |
| const XalanDocument& theDocument = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanDocument&)node; |
| #else |
| static_cast<const XalanDocument&>(node); |
| #endif |
| getNodeData(theDocument, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::ELEMENT_NODE: |
| { |
| const XalanElement& theElement = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanElement&)node; |
| #else |
| static_cast<const XalanElement&>(node); |
| #endif |
| getNodeData(theElement, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::TEXT_NODE: |
| case XalanNode::CDATA_SECTION_NODE: |
| { |
| const XalanText& theTextNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanText&)node; |
| #else |
| static_cast<const XalanText&>(node); |
| #endif |
| |
| getNodeData(theTextNode, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::ATTRIBUTE_NODE: |
| { |
| const XalanAttr& theAttr = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanAttr&)node; |
| #else |
| static_cast<const XalanAttr&>(node); |
| #endif |
| getNodeData(theAttr, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::COMMENT_NODE: |
| { |
| const XalanComment& theComment = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanComment&)node; |
| #else |
| static_cast<const XalanComment&>(node); |
| #endif |
| getNodeData(theComment, formatterListener, function); |
| } |
| break; |
| |
| case XalanNode::PROCESSING_INSTRUCTION_NODE: |
| { |
| const XalanProcessingInstruction& thePI = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanProcessingInstruction&)node; |
| #else |
| static_cast<const XalanProcessingInstruction&>(node); |
| #endif |
| getNodeData(thePI, formatterListener, function); |
| } |
| break; |
| |
| default: |
| // ignore |
| break; |
| } |
| } |
| |
| |
| |
| inline void |
| getChildData( |
| const XalanNode* child, |
| FormatterListener& formatterListener, |
| DOMServices::MemberFunctionPtr function) |
| { |
| const XalanNode::NodeType theType = child->getNodeType(); |
| |
| if (theType == XalanNode::ELEMENT_NODE) |
| { |
| const XalanElement* const theElementNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanElement*)child; |
| #else |
| static_cast<const XalanElement*>(child); |
| #endif |
| |
| DOMServices::getNodeData(*theElementNode, formatterListener, function); |
| } |
| else if (theType == XalanNode::TEXT_NODE || |
| theType == XalanNode::CDATA_SECTION_NODE) |
| { |
| const XalanText* theTextNode = |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanText*)child; |
| #else |
| static_cast<const XalanText*>(child); |
| #endif |
| |
| DOMServices::getNodeData(*theTextNode, formatterListener, function); |
| } |
| } |
| |
| |
| |
| inline void |
| getChildrenData( |
| const XalanNode* firstChild, |
| FormatterListener& formatterListener, |
| DOMServices::MemberFunctionPtr function) |
| { |
| while(firstChild != 0) |
| { |
| getChildData(firstChild, formatterListener, function); |
| |
| firstChild = firstChild->getNextSibling(); |
| } |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanDocument& document, |
| FormatterListener& formatterListener, |
| MemberFunctionPtr function) |
| { |
| getChildrenData(document.getDocumentElement(), formatterListener, function); |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanDocumentFragment& documentFragment, |
| FormatterListener& formatterListener, |
| MemberFunctionPtr function) |
| { |
| const XalanNodeList* const nl = documentFragment.getChildNodes(); |
| assert(nl != 0); |
| |
| const unsigned int n = nl->getLength(); |
| |
| for(unsigned int i = 0; i < n; ++i) |
| { |
| const XalanNode* const child = nl->item(i); |
| assert(child != 0); |
| |
| getChildData(child, formatterListener, function); |
| } |
| } |
| |
| |
| |
| void |
| DOMServices::getNodeData( |
| const XalanElement& element, |
| FormatterListener& formatterListener, |
| MemberFunctionPtr function) |
| { |
| getChildrenData(element.getFirstChild(), formatterListener, function); |
| } |
| |
| |
| |
| const XalanDOMString& |
| DOMServices::getNameOfNode(const XalanNode& n) |
| { |
| const XalanNode::NodeType theNodeType = |
| n.getNodeType(); |
| |
| if (theNodeType == XalanNode::ATTRIBUTE_NODE) |
| { |
| return getNameOfNode( |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanAttr&)n); |
| #else |
| static_cast<const XalanAttr&>(n)); |
| #endif |
| } |
| else if (theNodeType == XalanNode::ELEMENT_NODE) |
| { |
| return getNameOfNode( |
| #if defined(XALAN_OLD_STYLE_CASTS) |
| (const XalanElement&)n); |
| #else |
| static_cast<const XalanElement&>(n)); |
| #endif |
| } |
| else if (theNodeType == XalanNode::PROCESSING_INSTRUCTION_NODE) |
| { |
| return n.getNodeName(); |
| } |
| else |
| { |
| return s_emptyString; |
| } |
| } |
| |
| |
| |
| const XalanDOMString& |
| DOMServices::getNamespaceOfNode(const XalanNode& n) |
| { |
| if (n.getNodeType() != XalanNode::ATTRIBUTE_NODE) |
| { |
| return n.getNamespaceURI(); |
| } |
| else |
| { |
| const XalanDOMString& theNodeName = n.getNodeName(); |
| |
| // Special case for namespace nodes... |
| if (startsWith(theNodeName, DOMServices::s_XMLNamespaceWithSeparator) == true || |
| equals(theNodeName, DOMServices::s_XMLNamespace) == true) |
| { |
| return s_emptyString; |
| } |
| else |
| { |
| return n.getNamespaceURI(); |
| } |
| } |
| } |
| |
| |
| |
| // Note functional overlap with NamespaceResolver's |
| // getNamespaceOfNode() method. |
| // |
| // ***** Also: although this may not yet impact Xalan, |
| // as of DOM Level 2 it is possible for a hand-constructed DOM to |
| // have namespaced nodes with no declaration in scope. In DOM2 it's |
| // considered the responsibility of application code such as DOM |
| // serializers to recognize these cases and synthesize appropriate |
| // declarations when necessary. DOM3 is expected to add |
| // some form of namespaceNormalize() operation to assist this task. |
| // |
| // DOM3 may also add a resolveNamespacePrefix() operation |
| // which is aware of these issues and can generate reasonable |
| // results even for a non-NS-normalized tree. The expected logic |
| // is that a Namespaced node with a prefix will constitute an |
| // implicit declaration of that prefix. |
| // |
| // If we cut over to DOM2 and want to accept DOMs from sources other |
| // than the parser, we need to decide between demanding a |
| // namespace-normalized DOM as input, doing a normalize pass |
| // (full treewalk, expensive), or recognizing implicit declarations. |
| const XalanDOMString* |
| DOMServices::getNamespaceForPrefix( |
| const XalanDOMString& prefix, |
| const XalanElement& namespaceContext) |
| { |
| const XalanDOMString* theNamespace = 0; |
| |
| // Reserved xml: is hardcoded |
| if(equals(prefix, s_XMLString) == true) |
| { |
| theNamespace = &s_XMLNamespaceURI; |
| } |
| else |
| { |
| XalanNode::NodeType type; |
| const XalanNode* parent = &namespaceContext; |
| |
| // Consider elements until NS is resolved, or we run out of |
| // ancestors, or we hit something other than an Element or |
| // EntityReference node (ie, Document or DocumentFragment) |
| while (parent != 0 && theNamespace == 0 |
| && ((type = parent->getNodeType()) == XalanNode::ELEMENT_NODE |
| || type == XalanNode::ENTITY_REFERENCE_NODE)) |
| { |
| if (type == XalanNode::ELEMENT_NODE) |
| { |
| // Scan the attributes for xmlns:* or xmlns: |
| // (The latter is the prefix=="" case.) |
| const XalanNamedNodeMap* const nnm = parent->getAttributes(); |
| assert(nnm != 0); |
| |
| const unsigned int theLength = nnm->getLength(); |
| |
| for (unsigned int i = 0; i < theLength; i ++) |
| { |
| const XalanNode* const attr = nnm->item(i); |
| assert(attr != 0); |
| |
| const XalanDOMString& aname = attr->getNodeName(); |
| |
| const XalanDOMString::size_type len = length(aname); |
| |
| const bool isPrefix = len <= s_XMLNamespaceWithSeparatorLength ? false : |
| equals(substring(aname, |
| 0, |
| s_XMLNamespaceWithSeparatorLength), |
| s_XMLNamespaceWithSeparator); |
| |
| if (equals(aname, s_XMLNamespace) || isPrefix) |
| { |
| // slightly inefficient for default decl. |
| const XalanDOMString::size_type index = |
| indexOf(aname, XalanUnicode::charColon); |
| |
| const XalanDOMString p = isPrefix ? |
| substring(aname,index + 1,len) |
| : XalanDOMString(); |
| |
| if (equals(p, prefix) == true) |
| { |
| theNamespace = &attr->getNodeValue(); |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| parent = getParentOfNode(*parent); |
| } |
| } |
| |
| return theNamespace; |
| } |
| |
| |
| |
| bool |
| DOMServices::isNodeAfter( |
| const XalanNode& node1, |
| const XalanNode& node2) |
| { |
| assert(node1.getOwnerDocument() == node2.getOwnerDocument()); |
| assert(node1.getNodeType() != XalanNode::DOCUMENT_NODE && |
| node2.getNodeType() != XalanNode::DOCUMENT_NODE); |
| |
| if (node1.isIndexed() == true) |
| { |
| assert(node2.isIndexed() == true); |
| |
| return node1.getIndex() > node2.getIndex() ? true : false; |
| } |
| else |
| { |
| bool isNodeAfter = false; |
| |
| const XalanNode* parent1 = getParentOfNode(node1); |
| |
| const XalanNode* parent2 = getParentOfNode(node2); |
| |
| // Optimize for most common case |
| if(parent1 == parent2) // then we know they are siblings |
| { |
| isNodeAfter = isNodeAfterSibling(*parent1, |
| node1, |
| node2); |
| } |
| else |
| { |
| // General strategy: Figure out the lengths of the two |
| // ancestor chains, and walk up them looking for the |
| // first common ancestor, at which point we can do a |
| // sibling compare. Edge condition where one is the |
| // ancestor of the other. |
| |
| // Count parents, so we can see if one of the chains |
| // needs to be equalized. |
| int nParents1 = 2; |
| int nParents2 = 2; // count node & parent obtained above |
| |
| while(parent1 != 0) |
| { |
| nParents1++; |
| parent1 = getParentOfNode(*parent1); |
| } |
| |
| while(parent2 != 0) |
| { |
| nParents2++; |
| parent2 = getParentOfNode(*parent2); |
| } |
| |
| // adjustable starting points |
| const XalanNode* startNode1 = &node1; |
| const XalanNode* startNode2 = &node2; |
| |
| // Do I have to adjust the start point in one of |
| // the ancesor chains? |
| if(nParents1 < nParents2) |
| { |
| // adjust startNode2 |
| const int adjust = nParents2 - nParents1; |
| |
| for(int i = 0; i < adjust; i++) |
| { |
| startNode2 = getParentOfNode(*startNode2); |
| } |
| } |
| else if(nParents1 > nParents2) |
| { |
| // adjust startNode1 |
| const int adjust = nParents1 - nParents2; |
| |
| for(int i = 0; i < adjust; i++) |
| { |
| startNode1 = getParentOfNode(*startNode1); |
| } |
| } |
| |
| // so we can "back up" |
| const XalanNode* prevChild1 = 0; |
| const XalanNode* prevChild2 = 0; |
| |
| // Loop up the ancestor chain looking for common parent. |
| while(0 != startNode1) |
| { |
| if(startNode1 == startNode2) // common parent? |
| { |
| if(0 == prevChild1) // first time in loop? |
| { |
| // Edge condition: one is the ancestor of the other. |
| isNodeAfter = (nParents1 < nParents2) ? true : false; |
| |
| break; // from while loop |
| } |
| else |
| { |
| isNodeAfter = isNodeAfterSibling(*startNode1, |
| *prevChild1, |
| *prevChild2); |
| |
| break; // from while loop |
| } |
| } |
| |
| prevChild1 = startNode1; |
| assert(prevChild1 != 0); |
| |
| startNode1 = getParentOfNode(*startNode1); |
| assert(startNode1 != 0); |
| |
| prevChild2 = startNode2; |
| assert(prevChild2 != 0); |
| |
| startNode2 = getParentOfNode(*startNode2); |
| assert(startNode2 != 0); |
| } |
| } |
| |
| return isNodeAfter; |
| } |
| } |
| |
| |
| |
| bool |
| DOMServices::isNodeAfterSibling( |
| const XalanNode& parent, |
| const XalanNode& child1, |
| const XalanNode& child2) |
| { |
| bool isNodeAfterSibling = false; |
| |
| const XalanNode::NodeType child1type = child1.getNodeType(); |
| const XalanNode::NodeType child2type = child2.getNodeType(); |
| |
| if(XalanNode::ATTRIBUTE_NODE != child1type && |
| XalanNode::ATTRIBUTE_NODE == child2type) |
| { |
| // always sort attributes before non-attributes. |
| isNodeAfterSibling = true; |
| } |
| else if(XalanNode::ATTRIBUTE_NODE == child1type && |
| XalanNode::ATTRIBUTE_NODE != child2type) |
| { |
| // always sort attributes before non-attributes. |
| isNodeAfterSibling = false; |
| } |
| else if(XalanNode::ATTRIBUTE_NODE == child1type) |
| { |
| const XalanNamedNodeMap* children = parent.getAttributes(); |
| |
| const unsigned int nNodes = children->getLength(); |
| |
| bool found1 = false; |
| bool found2 = false; |
| |
| for(unsigned int i = 0; i < nNodes; i++) |
| { |
| const XalanNode* child = children->item(i); |
| |
| if(&child1 == child) |
| { |
| if(found2 == true) |
| { |
| isNodeAfterSibling = true; |
| break; |
| } |
| |
| found1 = true; |
| } |
| else if(&child2 == child) |
| { |
| if(found1 == true) |
| { |
| isNodeAfterSibling = false; |
| break; |
| } |
| |
| found2 = true; |
| } |
| } |
| } |
| else |
| { |
| const XalanNode* child = parent.getFirstChild(); |
| |
| bool found1 = false; |
| bool found2 = false; |
| |
| while(child != 0) |
| { |
| if(&child1 == child) |
| { |
| if(found2 == true) |
| { |
| isNodeAfterSibling = true; |
| break; |
| } |
| |
| found1 = true; |
| } |
| else if(&child2 == child) |
| { |
| if(found1 == true) |
| { |
| isNodeAfterSibling = false; |
| break; |
| } |
| |
| found2 = true; |
| } |
| |
| child = child->getNextSibling(); |
| } |
| |
| assert(found1 != found2); |
| } |
| |
| return isNodeAfterSibling; |
| } |
| |
| |
| |
| XalanNode* |
| DOMServices::findOwnerElement( |
| const XalanNode& attr, |
| XalanNode& element) |
| { |
| |
| XalanNode* parent = 0; |
| |
| const XalanNamedNodeMap* const attrs = element.getAttributes(); |
| |
| if(attrs != 0) |
| { |
| const unsigned int nAttrs = attrs->getLength(); |
| |
| for(unsigned int i = 0; i < nAttrs; i++) |
| { |
| if(attrs->item(i) == &attr) |
| { |
| parent = &element; |
| |
| break; |
| } |
| } |
| } |
| |
| if(parent == 0) |
| { |
| bool fFound = false; |
| |
| XalanNode* child = element.getFirstChild(); |
| |
| while(child != 0 && fFound == false) |
| { |
| if(child->getNodeType() == XalanNode::ELEMENT_NODE) |
| { |
| parent = findOwnerElement(attr, *child); |
| |
| if(parent != 0) |
| { |
| fFound = true; |
| } |
| } |
| |
| if (fFound == false) |
| { |
| child = child->getNextSibling(); |
| } |
| } |
| } |
| |
| return parent; |
| } |