From de6d1fc4706ac92d418c52001af88d472fc71f3b Mon Sep 17 00:00:00 2001 From: Alberto Massari <amassari@apache.org> Date: Wed, 28 Oct 2009 13:41:11 +0000 Subject: [PATCH] Implemented DOMLSParser::parseWithContext git-svn-id: https://svn.apache.org/repos/asf/xerces/c/trunk@830538 13f79535-47bb-0310-9956-ffa450edef68 --- doc/html/ApacheDOMC++Binding.html | 66 ++++++++++- doc/program-dom.xml | 13 +-- src/xercesc/dom/DOMErrorHandler.hpp | 2 +- src/xercesc/dom/DOMLSParser.hpp | 2 +- src/xercesc/internal/ElemStack.cpp | 124 ++++++++++++++++----- src/xercesc/internal/ElemStack.hpp | 34 +++--- src/xercesc/internal/IGXMLScanner.cpp | 2 +- src/xercesc/internal/IGXMLScanner.hpp | 2 +- src/xercesc/internal/IGXMLScanner2.cpp | 2 +- src/xercesc/internal/SGXMLScanner.cpp | 4 +- src/xercesc/internal/SGXMLScanner.hpp | 2 +- src/xercesc/internal/XMLScanner.hpp | 6 + src/xercesc/internal/XSAXMLScanner.cpp | 2 +- src/xercesc/parsers/DOMLSParserImpl.cpp | 142 +++++++++++++++++++++++- src/xercesc/parsers/DOMLSParserImpl.hpp | 20 +++- tests/src/DOM/DOMTest/DTest.cpp | 76 ++++++++++++- 16 files changed, 424 insertions(+), 75 deletions(-) diff --git a/doc/html/ApacheDOMC++Binding.html b/doc/html/ApacheDOMC++Binding.html index 47ff3cbef..57ffd6aa9 100644 --- a/doc/html/ApacheDOMC++Binding.html +++ b/doc/html/ApacheDOMC++Binding.html @@ -137,6 +137,13 @@ are owned by implementation</li> <br>- Updated to match the final DOM Level 3 Recommendation documents </td> </tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td>Xerces-C++ 3.1</td> +<td ALIGN=LEFT VALIGN=TOP>Modified +<br>- added DOM ElementTraversal +</td> +</tr> </table> <p> @@ -3141,6 +3148,61 @@ DOMElement <td><font face="Courier New,Courier"><font size=-1>getSchemaTypeInfo() const = 0; </font></font></td> </tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td></td> + +<td><font face="Courier New,Courier"><font size=-1>virtual</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>DOMElement *</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>getFirstElementChild() const = 0; +</font></font></td> +</tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td></td> + +<td><font face="Courier New,Courier"><font size=-1>virtual</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>DOMElement *</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>getLastElementChild() const = 0; +</font></font></td> +</tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td></td> + +<td><font face="Courier New,Courier"><font size=-1>virtual</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>DOMElement *</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>getPreviousElementSibling() const = 0; +</font></font></td> +</tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td></td> + +<td><font face="Courier New,Courier"><font size=-1>virtual</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>DOMElement *</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>getNextElementSibling() const = 0; +</font></font></td> +</tr> + +<tr ALIGN=LEFT VALIGN=TOP> +<td></td> + +<td><font face="Courier New,Courier"><font size=-1>virtual</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>XMLSize_t</font></font></td> + +<td><font face="Courier New,Courier"><font size=-1>getChildElementCount() const = 0; +</font></font></td> +</tr> <tr ALIGN=LEFT VALIGN=TOP> <td><font face="Courier New,Courier"><font size=-1>};</font></font></td> @@ -6750,7 +6812,7 @@ DOMXPathResult <td><font face="Courier New,Courier"><font size=-1>bool</font></font></td> -<td><font face="Courier New,Courier"><font size=-1>snapshotItem(XMLSize_t) = 0; +<td><font face="Courier New,Courier"><font size=-1>snapshotItem(XMLSize_t index) = 0; </font></font></td> </tr> @@ -6795,7 +6857,7 @@ DOMXPathResult <tr ALIGN=LEFT VALIGN=TOP> <td ALIGN=CENTER><i><font color="#0086B2"> <font size=-1> -Copyright © 1999-2008 The Apache Software Foundation. All Rights Reserved. +Copyright © 1999-2009 The Apache Software Foundation. All Rights Reserved. </font> </font> </i> diff --git a/doc/program-dom.xml b/doc/program-dom.xml index e855944e2..f34ade303 100644 --- a/doc/program-dom.xml +++ b/doc/program-dom.xml @@ -58,15 +58,6 @@ </ul> </s3> - <s3 title='Implementation of DOM Level 3 Load and Save'> - <p>The following are NOT implemented in &XercesCName; &XercesC3Version;.</p> - <ul> - <li> - <code>DOMLSParser</code>: parseWithContext(). - </li> - </ul> - - </s3> </s2> <anchor name="UsingDOMAPI"/> @@ -911,7 +902,7 @@ provides some framework classes for specialized types of input source (i.e. LocalFileInputSource, etc.) that are derived from the SAX InputSource. In DOM L3, to allow users implementing their own DOMLSResourceResolver(s), which return a DOMLSInput, to utilize these framework classes, we need to provide a mechanism to map a SAX InputSource to a - DOMInputSource. Two wrapper classes are available to interchange DOMLSInput and SAX InputSource: + DOMLSInput. Two wrapper classes are available to interchange DOMLSInput and SAX InputSource: </p> <s4 title="Wrapper4DOMLSInput"> @@ -1097,7 +1088,7 @@ <tr><th colspan="2"><em>namespaces</em></th></tr> <tr><th><em>true:</em></th><td> Perform Namespace processing </td></tr> <tr><th><em>false:</em></th><td> Do not perform Namespace processing</td></tr> - <tr><th><em>default:</em></th><td> false </td></tr> + <tr><th><em>default:</em></th><td> true </td></tr> <tr><th><em>XMLUni Predefined Constant:</em></th><td> fgDOMNamespaces </td></tr> <tr><th><em>note:</em></th><td> If the validation is on, then the document must contain a grammar that supports the use of namespaces </td></tr> diff --git a/src/xercesc/dom/DOMErrorHandler.hpp b/src/xercesc/dom/DOMErrorHandler.hpp index 00f262b9e..b2c8101bc 100644 --- a/src/xercesc/dom/DOMErrorHandler.hpp +++ b/src/xercesc/dom/DOMErrorHandler.hpp @@ -88,7 +88,7 @@ public: * * @param domError The error object that describes the error, this object * may be reused by the DOM implementation across multiple - * calls to the handleEvent method. + * calls to the handleError method. * @return If the handleError method returns <code>true</code> the DOM * implementation should continue as if the error didn't happen * when possible, if the method returns <code>false</code> then the diff --git a/src/xercesc/dom/DOMLSParser.hpp b/src/xercesc/dom/DOMLSParser.hpp index 6a2f099fa..216219c49 100644 --- a/src/xercesc/dom/DOMLSParser.hpp +++ b/src/xercesc/dom/DOMLSParser.hpp @@ -584,7 +584,7 @@ public: * if they wish to get details on the error. * @since DOM Level 3 */ - virtual void parseWithContext + virtual DOMNode* parseWithContext ( const DOMLSInput* source , DOMNode* contextNode diff --git a/src/xercesc/internal/ElemStack.cpp b/src/xercesc/internal/ElemStack.cpp index f80049ae2..baff8452b 100644 --- a/src/xercesc/internal/ElemStack.cpp +++ b/src/xercesc/internal/ElemStack.cpp @@ -39,6 +39,7 @@ ElemStack::ElemStack(MemoryManager* const manager) : fEmptyNamespaceId(0) , fGlobalPoolId(0) , fPrefixPool(109, manager) + , fGlobalNamespaces(0) , fStack(0) , fStackCapacity(32) , fStackTop(0) @@ -62,11 +63,17 @@ ElemStack::ElemStack(MemoryManager* const manager) : ElemStack::~ElemStack() { + if(fGlobalNamespaces) + { + fMemoryManager->deallocate(fGlobalNamespaces->fMap); + delete fGlobalNamespaces; + } + // // Start working from the bottom of the stack and clear it out as we // go up. Once we hit an uninitialized one, we can break out. // - for (unsigned int stackInd = 0; stackInd < fStackCapacity; stackInd++) + for (XMLSize_t stackInd = 0; stackInd < fStackCapacity; stackInd++) { // If this entry has been set, then lets clean it up if (!fStack[stackInd]) @@ -87,7 +94,7 @@ ElemStack::~ElemStack() // --------------------------------------------------------------------------- // ElemStack: Stack access // --------------------------------------------------------------------------- -unsigned int ElemStack::addLevel() +XMLSize_t ElemStack::addLevel() { // See if we need to expand the stack if (fStackTop == fStackCapacity) @@ -124,8 +131,7 @@ unsigned int ElemStack::addLevel() } -unsigned int -ElemStack::addLevel(XMLElementDecl* const toSet, const XMLSize_t readerNum) +XMLSize_t ElemStack::addLevel(XMLElementDecl* const toSet, const XMLSize_t readerNum) { // See if we need to expand the stack if (fStackTop == fStackCapacity) @@ -208,9 +214,9 @@ XMLSize_t ElemStack::addChild(QName* const child, const bool toParent) if (curRow->fChildCount == curRow->fChildCapacity) { // Increase the capacity by a quarter and allocate a new row - const unsigned int newCapacity = curRow->fChildCapacity ? - (unsigned int)(curRow->fChildCapacity * 1.25) : - 32; + const XMLSize_t newCapacity = curRow->fChildCapacity ? + (XMLSize_t)(curRow->fChildCapacity * 1.25) : + 32; QName** newRow = (QName**) fMemoryManager->allocate ( newCapacity * sizeof(QName*) @@ -225,12 +231,8 @@ XMLSize_t ElemStack::addChild(QName* const child, const bool toParent) // this code also does the initial faulting in of the array when // both the current capacity and child count are zero. // - if (curRow->fChildCount) - { - unsigned int index = 0; - for (; index < curRow->fChildCount; index++) - newRow[index] = curRow->fChildren[index]; - } + for (XMLSize_t index = 0; index < curRow->fChildCount; index++) + newRow[index] = curRow->fChildren[index]; // Clean up the old children and store the new info fMemoryManager->deallocate(curRow->fChildren);//delete [] curRow->fChildren; @@ -257,6 +259,54 @@ const ElemStack::StackElem* ElemStack::topElement() const // --------------------------------------------------------------------------- // ElemStack: Prefix map methods // --------------------------------------------------------------------------- +void ElemStack::addGlobalPrefix(const XMLCh* const prefixToAdd + , const unsigned int uriId) +{ + if (!fGlobalNamespaces) + { + fGlobalNamespaces = new (fMemoryManager) StackElem; + fGlobalNamespaces->fChildCapacity = 0; + fGlobalNamespaces->fChildren = 0; + fGlobalNamespaces->fMapCapacity = 0; + fGlobalNamespaces->fMap = 0; + fGlobalNamespaces->fMapCount = 0; + fGlobalNamespaces->fSchemaElemName = 0; + fGlobalNamespaces->fSchemaElemNameMaxLen = 0; + fGlobalNamespaces->fThisElement = 0; + fGlobalNamespaces->fReaderNum = 0xFFFFFFFF; + fGlobalNamespaces->fChildCount = 0; + fGlobalNamespaces->fValidationFlag = false; + fGlobalNamespaces->fCommentOrPISeen = false; + fGlobalNamespaces->fReferenceEscaped = false; + fGlobalNamespaces->fCurrentURI = fUnknownNamespaceId; + fGlobalNamespaces->fCurrentScope = Grammar::TOP_LEVEL_SCOPE; + fGlobalNamespaces->fCurrentGrammar = 0; + } + + // Map the prefix to its unique id + const unsigned int prefId = fPrefixPool.addOrFind(prefixToAdd); + + // + // Add a new element to the prefix map for this element. If its full, + // then expand it out. + // + if (fGlobalNamespaces->fMapCount == fGlobalNamespaces->fMapCapacity) + expandMap(fGlobalNamespaces); + + // + // And now add a new element for this prefix. Watch for the special case + // of xmlns=="", and force it to ""=[globalid] + // + fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fPrefId = prefId; + if ((prefId == fGlobalPoolId) && (uriId == fEmptyNamespaceId)) + fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fURIId = fEmptyNamespaceId; + else + fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fURIId = uriId; + + // Bump the map count now + fGlobalNamespaces->fMapCount++; +} + void ElemStack::addPrefix( const XMLCh* const prefixToAdd , const unsigned int uriId) { @@ -320,19 +370,27 @@ unsigned int ElemStack::mapPrefixToURI( const XMLCh* const prefixToMap // Start at the stack top and work backwards until we come to some // element that mapped this prefix. // - unsigned int index, mapIndex; - for (index = fStackTop; index > 0; index--) + for (XMLSize_t index = fStackTop; index > 0; index--) { // Get a convenience pointer to the current element StackElem* curRow = fStack[index-1]; // Search the map at this level for the passed prefix - for (mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++) + for (XMLSize_t mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++) { if (curRow->fMap[mapIndex].fPrefId == prefixId) return curRow->fMap[mapIndex].fURIId; } } + // If the prefix wasn't found, try in the global namespaces + if(fGlobalNamespaces) + { + for (XMLSize_t mapIndex = 0; mapIndex < fGlobalNamespaces->fMapCount; mapIndex++) + { + if (fGlobalNamespaces->fMap[mapIndex].fPrefId == prefixId) + return fGlobalNamespaces->fMap[mapIndex].fURIId; + } + } // // If the prefix is an empty string, then we will return the special @@ -354,21 +412,24 @@ ValueVectorOf<PrefMapElem*>* ElemStack::getNamespaceMap() const // Start at the stack top and work backwards until we come to some // element that mapped this prefix. - int startAt = (int)(fStackTop - 1); - for (int index = startAt; index >= 0; index--) + for (XMLSize_t index = fStackTop; index > 0; index--) { // Get a convenience pointer to the current element - StackElem* curRow = fStack[index]; + StackElem* curRow = fStack[index-1]; // If no prefixes mapped at this level, then go the next one if (!curRow->fMapCount) continue; // Search the map at this level for the passed prefix - for (unsigned int mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++) - { + for (XMLSize_t mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++) fNamespaceMap->addElement(&(curRow->fMap[mapIndex])); - } + } + // Add the global namespaces + if(fGlobalNamespaces) + { + for (XMLSize_t mapIndex = 0; mapIndex < fGlobalNamespaces->fMapCount; mapIndex++) + fNamespaceMap->addElement(&(fGlobalNamespaces->fMap[mapIndex])); } return fNamespaceMap; @@ -382,6 +443,13 @@ void ElemStack::reset( const unsigned int emptyId , const unsigned int xmlId , const unsigned int xmlNSId) { + if(fGlobalNamespaces) + { + fMemoryManager->deallocate(fGlobalNamespaces->fMap); + delete fGlobalNamespaces; + fGlobalNamespaces = 0; + } + // Reset the stack top to clear the stack fStackTop = 0; @@ -499,7 +567,7 @@ WFElemStack::~WFElemStack() // Start working from the bottom of the stack and clear it out as we // go up. Once we hit an uninitialized one, we can break out. // - for (unsigned int stackInd = 0; stackInd < fStackCapacity; stackInd++) + for (XMLSize_t stackInd = 0; stackInd < fStackCapacity; stackInd++) { // If this entry has been set, then lets clean it up if (!fStack[stackInd]) @@ -520,7 +588,7 @@ WFElemStack::~WFElemStack() // --------------------------------------------------------------------------- // WFElemStack: Stack access // --------------------------------------------------------------------------- -unsigned int WFElemStack::addLevel() +XMLSize_t WFElemStack::addLevel() { // See if we need to expand the stack if (fStackTop == fStackCapacity) @@ -550,7 +618,7 @@ unsigned int WFElemStack::addLevel() } -unsigned int +XMLSize_t WFElemStack::addLevel(const XMLCh* const toSet, const unsigned int toSetLen, const unsigned int readerNum) @@ -767,8 +835,8 @@ void WFElemStack::expandMap() // Expand the capacity by 25%, or initialize it to 16 if its currently // empty. Then allocate a new temp buffer. // - const unsigned int newCapacity = fMapCapacity ? - (unsigned int)(fMapCapacity * 1.25) : 16; + const XMLSize_t newCapacity = fMapCapacity ? + (XMLSize_t)(fMapCapacity * 1.25) : 16; PrefMapElem* newMap = (PrefMapElem*) fMemoryManager->allocate ( newCapacity * sizeof(PrefMapElem) @@ -792,7 +860,7 @@ void WFElemStack::expandMap() void WFElemStack::expandStack() { // Expand the capacity by 25% and allocate a new buffer - const unsigned int newCapacity = (unsigned int)(fStackCapacity * 1.25); + const XMLSize_t newCapacity = (XMLSize_t)(fStackCapacity * 1.25); StackElem** newStack = (StackElem**) fMemoryManager->allocate ( newCapacity * sizeof(StackElem*) diff --git a/src/xercesc/internal/ElemStack.hpp b/src/xercesc/internal/ElemStack.hpp index 95667ba37..4634ae0a2 100644 --- a/src/xercesc/internal/ElemStack.hpp +++ b/src/xercesc/internal/ElemStack.hpp @@ -138,8 +138,8 @@ public : // ----------------------------------------------------------------------- // Stack access // ----------------------------------------------------------------------- - unsigned int addLevel(); - unsigned int addLevel(XMLElementDecl* const toSet, const XMLSize_t readerNum); + XMLSize_t addLevel(); + XMLSize_t addLevel(XMLElementDecl* const toSet, const XMLSize_t readerNum); const StackElem* popTop(); @@ -177,6 +177,11 @@ public : // ----------------------------------------------------------------------- // Prefix map methods // ----------------------------------------------------------------------- + void addGlobalPrefix + ( + const XMLCh* const prefixToAdd + , const unsigned int uriId + ); void addPrefix ( const XMLCh* const prefixToAdd @@ -238,6 +243,9 @@ private : // This is the prefix pool where prefixes are hashed and given unique // ids. These ids are used to track prefixes in the element stack. // + // fGlobalNamespaces + // This object contains the namespace bindings that are globally valid + // // fStack // fStackCapacity // fStackTop @@ -262,9 +270,10 @@ private : unsigned int fEmptyNamespaceId; unsigned int fGlobalPoolId; XMLStringPool fPrefixPool; + StackElem* fGlobalNamespaces; StackElem** fStack; XMLSize_t fStackCapacity; - unsigned int fStackTop; + XMLSize_t fStackTop; unsigned int fUnknownNamespaceId; unsigned int fXMLNamespaceId; unsigned int fXMLPoolId; @@ -333,8 +342,8 @@ public : // ----------------------------------------------------------------------- // Stack access // ----------------------------------------------------------------------- - unsigned int addLevel(); - unsigned int addLevel(const XMLCh* const toSet, const unsigned int toSetLen, + XMLSize_t addLevel(); + XMLSize_t addLevel(const XMLCh* const toSet, const unsigned int toSetLen, const unsigned int readerNum); const StackElem* popTop(); @@ -433,14 +442,14 @@ private : // ----------------------------------------------------------------------- unsigned int fEmptyNamespaceId; unsigned int fGlobalPoolId; - unsigned int fStackCapacity; - unsigned int fStackTop; + XMLSize_t fStackCapacity; + XMLSize_t fStackTop; unsigned int fUnknownNamespaceId; unsigned int fXMLNamespaceId; unsigned int fXMLPoolId; unsigned int fXMLNSNamespaceId; unsigned int fXMLNSPoolId; - unsigned int fMapCapacity; + XMLSize_t fMapCapacity; PrefMapElem* fMap; StackElem** fStack; XMLStringPool fPrefixPool; @@ -464,7 +473,6 @@ inline bool ElemStack::getValidationFlag() inline void ElemStack::setValidationFlag(bool validationFlag) { fStack[fStackTop-1]->fValidationFlag = validationFlag; - return; } inline bool ElemStack::getCommentOrPISeen() const @@ -475,7 +483,6 @@ inline bool ElemStack::getCommentOrPISeen() const inline void ElemStack::setCommentOrPISeen() { fStack[fStackTop-1]->fCommentOrPISeen = true; - return; } inline bool ElemStack::getReferenceEscaped() const @@ -486,13 +493,12 @@ inline bool ElemStack::getReferenceEscaped() const inline void ElemStack::setReferenceEscaped() { fStack[fStackTop-1]->fReferenceEscaped = true; - return; } inline void ElemStack::setCurrentSchemaElemName(const XMLCh * const schemaElemName) { XMLSize_t schemaElemNameLen = XMLString::stringLen(schemaElemName); - unsigned int stackPos = fStackTop-1; + XMLSize_t stackPos = fStackTop-1; if(fStack[stackPos]->fSchemaElemNameMaxLen <= schemaElemNameLen) { @@ -517,7 +523,6 @@ inline int ElemStack::getCurrentScope() inline void ElemStack::setCurrentScope(int currentScope) { fStack[fStackTop-1]->fCurrentScope = currentScope; - return; } inline Grammar* ElemStack::getCurrentGrammar() @@ -528,7 +533,6 @@ inline Grammar* ElemStack::getCurrentGrammar() inline void ElemStack::setCurrentGrammar(Grammar* currentGrammar) { fStack[fStackTop-1]->fCurrentGrammar = currentGrammar; - return; } inline unsigned int ElemStack::getCurrentURI() @@ -539,7 +543,6 @@ inline unsigned int ElemStack::getCurrentURI() inline void ElemStack::setCurrentURI(unsigned int uri) { fStack[fStackTop-1]->fCurrentURI = uri; - return; } inline unsigned int ElemStack::getPrefixId(const XMLCh* const prefix) const @@ -581,7 +584,6 @@ inline unsigned int WFElemStack::getCurrentURI() inline void WFElemStack::setCurrentURI(unsigned int uri) { fStack[fStackTop-1]->fCurrentURI = uri; - return; } diff --git a/src/xercesc/internal/IGXMLScanner.cpp b/src/xercesc/internal/IGXMLScanner.cpp index 3b717a799..4e5ce1af6 100644 --- a/src/xercesc/internal/IGXMLScanner.cpp +++ b/src/xercesc/internal/IGXMLScanner.cpp @@ -2182,7 +2182,7 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData) // Now, since we might have to update the namespace map for this element, // but we don't have the element decl yet, we just tell the element stack // to expand up to get ready. - unsigned int elemDepth = fElemStack.addLevel(); + XMLSize_t elemDepth = fElemStack.addLevel(); fElemStack.setValidationFlag(fValidate); fElemStack.setPrefixColonPos(prefixColonPos); diff --git a/src/xercesc/internal/IGXMLScanner.hpp b/src/xercesc/internal/IGXMLScanner.hpp index 343d54ac3..e0a385293 100644 --- a/src/xercesc/internal/IGXMLScanner.hpp +++ b/src/xercesc/internal/IGXMLScanner.hpp @@ -160,7 +160,7 @@ private : bool switchGrammar(const XMLCh* const newGrammarNameSpace); bool laxElementValidation(QName* element, ContentLeafNameTypeVector* cv, const XMLContentModel* const cm, - const unsigned int parentElemDepth); + const XMLSize_t parentElemDepth); bool anyAttributeValidation(SchemaAttDef* attWildCard, unsigned int uriId, bool& skipThisOne, diff --git a/src/xercesc/internal/IGXMLScanner2.cpp b/src/xercesc/internal/IGXMLScanner2.cpp index f801a8f14..c2ec31e79 100644 --- a/src/xercesc/internal/IGXMLScanner2.cpp +++ b/src/xercesc/internal/IGXMLScanner2.cpp @@ -3148,7 +3148,7 @@ bool IGXMLScanner::switchGrammar(const XMLCh* const newGrammarNameSpace) // if lax - validate only if the element if found bool IGXMLScanner::laxElementValidation(QName* element, ContentLeafNameTypeVector* cv, const XMLContentModel* const cm, - const unsigned int parentElemDepth) + const XMLSize_t parentElemDepth) { bool skipThisOne = false; bool laxThisOne = false; diff --git a/src/xercesc/internal/SGXMLScanner.cpp b/src/xercesc/internal/SGXMLScanner.cpp index f5eff4ea4..ae3de7615 100644 --- a/src/xercesc/internal/SGXMLScanner.cpp +++ b/src/xercesc/internal/SGXMLScanner.cpp @@ -1157,7 +1157,7 @@ bool SGXMLScanner::scanStartTag(bool& gotData) // Now, since we might have to update the namespace map for this element, // but we don't have the element decl yet, we just tell the element stack // to expand up to get ready. - unsigned int elemDepth = fElemStack.addLevel(); + XMLSize_t elemDepth = fElemStack.addLevel(); fElemStack.setValidationFlag(fValidate); fElemStack.setPrefixColonPos(prefixColonPos); @@ -4554,7 +4554,7 @@ bool SGXMLScanner::switchGrammar(const XMLCh* const newGrammarNameSpace) // if lax - validate only if the element if found bool SGXMLScanner::laxElementValidation(QName* element, ContentLeafNameTypeVector* cv, const XMLContentModel* const cm, - const unsigned int parentElemDepth) + const XMLSize_t parentElemDepth) { bool skipThisOne = false; bool laxThisOne = false; diff --git a/src/xercesc/internal/SGXMLScanner.hpp b/src/xercesc/internal/SGXMLScanner.hpp index 2bfe29018..05bdd4234 100644 --- a/src/xercesc/internal/SGXMLScanner.hpp +++ b/src/xercesc/internal/SGXMLScanner.hpp @@ -112,7 +112,7 @@ protected: ); bool laxElementValidation(QName* element, ContentLeafNameTypeVector* cv, const XMLContentModel* const cm, - const unsigned int parentElemDepth); + const XMLSize_t parentElemDepth); XMLSize_t rawAttrScan ( const XMLCh* const elemName diff --git a/src/xercesc/internal/XMLScanner.hpp b/src/xercesc/internal/XMLScanner.hpp index 0d61e85a6..41efc7887 100644 --- a/src/xercesc/internal/XMLScanner.hpp +++ b/src/xercesc/internal/XMLScanner.hpp @@ -343,6 +343,7 @@ public : // ----------------------------------------------------------------------- // Setter methods // ----------------------------------------------------------------------- + void addGlobalPrefix(const XMLCh* const prefix, const unsigned int uriId); void setDocHandler(XMLDocumentHandler* const docHandler); void setDocTypeHandler(DocTypeHandler* const docTypeHandler); void setDoNamespaces(const bool doNamespaces); @@ -1160,6 +1161,11 @@ inline bool XMLScanner::getHandleMultipleImports() const // --------------------------------------------------------------------------- // XMLScanner: Setter methods // --------------------------------------------------------------------------- +inline void XMLScanner::addGlobalPrefix(const XMLCh* const prefix, const unsigned int uriId) +{ + fElemStack.addGlobalPrefix(prefix, uriId); +} + inline void XMLScanner::setDocHandler(XMLDocumentHandler* const docHandler) { fDocHandler = docHandler; diff --git a/src/xercesc/internal/XSAXMLScanner.cpp b/src/xercesc/internal/XSAXMLScanner.cpp index dac164ec8..075796c10 100644 --- a/src/xercesc/internal/XSAXMLScanner.cpp +++ b/src/xercesc/internal/XSAXMLScanner.cpp @@ -267,7 +267,7 @@ bool XSAXMLScanner::scanStartTag(bool& gotData) // Now, since we might have to update the namespace map for this element, // but we don't have the element decl yet, we just tell the element stack // to expand up to get ready. - unsigned int elemDepth = fElemStack.addLevel(); + XMLSize_t elemDepth = fElemStack.addLevel(); fElemStack.setValidationFlag(fValidate); fElemStack.setPrefixColonPos(prefixColonPos); diff --git a/src/xercesc/parsers/DOMLSParserImpl.cpp b/src/xercesc/parsers/DOMLSParserImpl.cpp index c729f8613..bff6ae5b6 100644 --- a/src/xercesc/parsers/DOMLSParserImpl.cpp +++ b/src/xercesc/parsers/DOMLSParserImpl.cpp @@ -38,8 +38,11 @@ #include <xercesc/dom/impl/DOMLocatorImpl.hpp> #include <xercesc/dom/impl/DOMConfigurationImpl.hpp> #include <xercesc/dom/impl/DOMStringListImpl.hpp> +#include <xercesc/dom/impl/DOMDocumentImpl.hpp> #include <xercesc/dom/DOMException.hpp> #include <xercesc/dom/DOMLSException.hpp> +#include <xercesc/dom/DOMDocumentFragment.hpp> +#include <xercesc/dom/DOMNamedNodeMap.hpp> #include <xercesc/internal/XMLScanner.hpp> #include <xercesc/framework/Wrapper4DOMLSInput.hpp> #include <xercesc/framework/XMLGrammarPool.hpp> @@ -85,6 +88,8 @@ AbstractDOMParser(valToAdopt, manager, gramPool) , fSupportedParameters(0) , fFilterAction(0) , fFilterDelayedTextNodes(0) +, fWrapNodesInDocumentFragment(0) +, fWrapNodesContext(0) { // dom spec has different default from scanner's default, so set explicitly getScanner()->setNormalizeData(false); @@ -140,6 +145,9 @@ AbstractDOMParser(valToAdopt, manager, gramPool) fSupportedParameters->add(XMLUni::fgXercesSkipDTDValidation); fSupportedParameters->add(XMLUni::fgXercesDoXInclude); fSupportedParameters->add(XMLUni::fgXercesHandleMultipleImports); + + // LSParser by default does namespace processing + setDoNamespaces(true); } @@ -790,9 +798,70 @@ DOMDocument* DOMLSParserImpl::parseURI(const char* const systemId) return getDocument(); } -void DOMLSParserImpl::parseWithContext(const DOMLSInput*, - DOMNode* , - const ActionType) +void DOMLSParserImpl::startDocument() +{ + if(fWrapNodesInDocumentFragment) + { + fDocument = (DOMDocumentImpl*)fWrapNodesInDocumentFragment->getOwnerDocument(); + fCurrentParent = fCurrentNode = fWrapNodesInDocumentFragment; + // set DOM error checking off + fDocument->setErrorChecking(false); + + // if we have namespaces in scope, push them down to the reader + ValueHashTableOf<unsigned int> inScopeNS(7, fMemoryManager); + DOMNode* cursor = fWrapNodesContext; + while(cursor) + { + if(cursor->getNodeType()==DOMNode::ELEMENT_NODE) + { + DOMNamedNodeMap* attrs = cursor->getAttributes(); + for(XMLSize_t i=0; i<attrs->getLength(); i++) + { + DOMNode* attr = attrs->item(i); + if(XMLString::equals(attr->getNamespaceURI(), XMLUni::fgXMLNSURIName) && !inScopeNS.containsKey(attr->getLocalName())) + inScopeNS.put((void*)attr->getLocalName(), fScanner->getURIStringPool()->addOrFind(attr->getNodeValue())); + else if(XMLString::equals(attr->getNodeName(), XMLUni::fgXMLNSString) && !inScopeNS.containsKey(XMLUni::fgZeroLenString)) + inScopeNS.put((void*)XMLUni::fgZeroLenString, fScanner->getURIStringPool()->addOrFind(attr->getNodeValue())); + } + } + cursor = cursor->getParentNode(); + } + ValueHashTableOfEnumerator<unsigned int> iter(&inScopeNS, false, fMemoryManager); + while(iter.hasMoreElements()) + { + XMLCh* prefix = (XMLCh*)iter.nextElementKey(); + fScanner->addGlobalPrefix(prefix, inScopeNS.get(prefix)); + } + + // in this case the document URI and the input encoding must be propagated to the context document + if(fWrapNodesAction==ACTION_REPLACE_CHILDREN && fWrapNodesContext->getNodeType()==DOMNode::DOCUMENT_NODE) + { + fDocument->setDocumentURI(fScanner->getLocator()->getSystemId()); + fDocument->setInputEncoding(fScanner->getReaderMgr()->getCurrentEncodingStr()); + } + } + else + AbstractDOMParser::startDocument(); +} + +void DOMLSParserImpl::XMLDecl( const XMLCh* const versionStr + , const XMLCh* const encodingStr + , const XMLCh* const standaloneStr + , const XMLCh* const actualEncStr + ) +{ + if(fWrapNodesInDocumentFragment && !(fWrapNodesAction==ACTION_REPLACE_CHILDREN && fWrapNodesContext->getNodeType()==DOMNode::DOCUMENT_NODE)) + { + // don't change the properties for the context document, unless the context node is a + // DOMDocument node and the action is ACTION_REPLACE_CHILDREN + } + else + AbstractDOMParser::XMLDecl(versionStr, encodingStr, standaloneStr, actualEncStr); +} + +DOMNode* DOMLSParserImpl::parseWithContext(const DOMLSInput* source, + DOMNode* contextNode, + const ActionType action) { if (getParseInProgress()) throw DOMException(DOMException::INVALID_STATE_ERR, XMLDOMMsg::LSParser_ParseInProgress, fMemoryManager); @@ -805,8 +874,71 @@ void DOMLSParserImpl::parseWithContext(const DOMLSInput*, if(fFilterDelayedTextNodes) fFilterDelayedTextNodes->removeAll(); - // TODO - throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, getMemoryManager()); + DOMDocumentFragment* holder = contextNode->getOwnerDocument()->createDocumentFragment(); + // When parsing the input stream, the context node (or its parent, depending on where + // the result will be inserted) is used for resolving unbound namespace prefixes + if(action==ACTION_INSERT_BEFORE || action==ACTION_INSERT_AFTER || action==ACTION_REPLACE) + fWrapNodesContext = contextNode->getParentNode(); + else + fWrapNodesContext = contextNode; + fWrapNodesInDocumentFragment = holder; + fWrapNodesAction = action; + // When calling parseWithContext, the values of the following configuration parameters + // will be ignored and their default values will always be used instead: "validate", + // "validate-if-schema", and "element-content-whitespace". + ValSchemes oldValidate = getValidationScheme(); + setValidationScheme(Val_Never); + bool oldElementContentWhitespace = getIncludeIgnorableWhitespace(); + setIncludeIgnorableWhitespace(true); + + Wrapper4DOMLSInput isWrapper((DOMLSInput*)source, fEntityResolver, false, getMemoryManager()); + AbstractDOMParser::parse(isWrapper); + + setValidationScheme(oldValidate); + setIncludeIgnorableWhitespace(oldElementContentWhitespace); + fWrapNodesContext = NULL; + fWrapNodesInDocumentFragment = NULL; + fDocument = NULL; + + if(getErrorCount()!=0) + { + holder->release(); + throw DOMLSException(DOMLSException::PARSE_ERR, XMLDOMMsg::LSParser_ParsingFailed, fMemoryManager); + } + + DOMNode* result = holder->getFirstChild(); + DOMNode* node, *parent = contextNode->getParentNode(); + switch(action) + { + case ACTION_REPLACE_CHILDREN: + // remove existing children + while((node = contextNode->getFirstChild())!=NULL) + contextNode->removeChild(node)->release(); + // then fall back to behave like an append + case ACTION_APPEND_AS_CHILDREN: + while((node = holder->getFirstChild())!=NULL) + contextNode->appendChild(holder->removeChild(node)); + break; + case ACTION_INSERT_BEFORE: + while((node = holder->getFirstChild())!=NULL) + parent->insertBefore(holder->removeChild(node), contextNode); + break; + case ACTION_INSERT_AFTER: + while((node = holder->getLastChild())!=NULL) + parent->insertBefore(holder->removeChild(node), contextNode->getNextSibling()); + break; + case ACTION_REPLACE: + while((node = holder->getFirstChild())!=NULL) + parent->insertBefore(holder->removeChild(node), contextNode); + parent->removeChild(contextNode)->release(); + break; + } + holder->release(); + + // TODO whenever we add support for DOM Mutation Events: + // As the new data is inserted into the document, at least one mutation event is fired + // per new immediate child or sibling of the context node. + return result; } void DOMLSParserImpl::abort() diff --git a/src/xercesc/parsers/DOMLSParserImpl.hpp b/src/xercesc/parsers/DOMLSParserImpl.hpp index 9f053ab84..6e3bf0e04 100644 --- a/src/xercesc/parsers/DOMLSParserImpl.hpp +++ b/src/xercesc/parsers/DOMLSParserImpl.hpp @@ -156,7 +156,7 @@ public : /** * @see DOMLSParser#parseWithContext */ - virtual void parseWithContext + virtual DOMNode* parseWithContext ( const DOMLSInput* source , DOMNode* contextNode @@ -578,6 +578,16 @@ public : , const bool isRoot ); + // overriden callbacks to implement parseWithContext behavior + virtual void startDocument(); + virtual void XMLDecl + ( + const XMLCh* const versionStr + , const XMLCh* const encodingStr + , const XMLCh* const standaloneStr + , const XMLCh* const actualEncStr + ); + private : // ----------------------------------------------------------------------- @@ -627,6 +637,11 @@ private : // so that we ask DOMLSParserFilter::acceptNode only once, when it // is completely created // + // fWrapNodesInDocumentFragment + // fWrapNodesContext + // fWrapNodesAction + // Variables used to keep the state for parseWithContext API + // //----------------------------------------------------------------------- DOMLSResourceResolver* fEntityResolver; XMLEntityResolver* fXMLEntityResolver; @@ -637,6 +652,9 @@ private : DOMStringListImpl* fSupportedParameters; ValueHashTableOf<DOMLSParserFilter::FilterAction, PtrHasher>* fFilterAction; ValueHashTableOf<bool, PtrHasher>* fFilterDelayedTextNodes; + DOMDocumentFragment* fWrapNodesInDocumentFragment; + DOMNode* fWrapNodesContext; + ActionType fWrapNodesAction; // ----------------------------------------------------------------------- // Unimplemented constructors and operators diff --git a/tests/src/DOM/DOMTest/DTest.cpp b/tests/src/DOM/DOMTest/DTest.cpp index 85ab26edb..f73164091 100644 --- a/tests/src/DOM/DOMTest/DTest.cpp +++ b/tests/src/DOM/DOMTest/DTest.cpp @@ -5042,8 +5042,8 @@ bool DOMTest::testLSExceptions() { // this XML should trigger reuse of DOMElement const char* sXml2="<?xml version='1.0'?>" - "<root>" - "<elem>Home</elem>" + "<root xmlns:x='urn:yyy'>" + "<elem xmlns:x='urn:xxx'>Home</elem>" "<elem2>Test</elem2>" "<elem>Home</elem>" "<elem2>Test</elem2>" @@ -5069,6 +5069,76 @@ bool DOMTest::testLSExceptions() { OK=false; } + // test for parseWithContext + try + { + XMLString::transcode("root", tempStr2, 3999); + domBuilder->setFilter(NULL); + DOMDocument* doc=domBuilder->parse(input); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_APPEND_AS_CHILDREN); + // the first 'elem' child of 'root' must have a 'root' child + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getFirstElementChild()->getNodeName(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + + doc=domBuilder->parse(input); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_REPLACE_CHILDREN); + // the first 'elem' child of 'root' must have a 'root' child + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getFirstElementChild()->getNodeName(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + + doc=domBuilder->parse(input); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_INSERT_BEFORE); + // the first child of 'root' must be another 'root' child + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getNodeName(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + + doc=domBuilder->parse(input); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_INSERT_AFTER); + // the node after the first child of 'root' must be another 'root' child + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getNextElementSibling()->getNodeName(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + + doc=domBuilder->parse(input); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_REPLACE); + // the first child of 'root' must be another 'root' child + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getNodeName(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + + // verify that namespaces are in scope + doc=domBuilder->parse(input); + const char* sXml3="<x:root/>"; + XMLString::transcode(sXml3, tempStr2, 3999); + input->setStringData(tempStr2); + domBuilder->parseWithContext(input, doc->getDocumentElement()->getFirstElementChild(), DOMLSParser::ACTION_APPEND_AS_CHILDREN); + // the first 'elem' child of 'root' must have a 'x:root' child + XMLString::transcode("urn:xxx", tempStr2, 3999); + if(!XMLString::equals(doc->getDocumentElement()->getFirstElementChild()->getFirstElementChild()->getNamespaceURI(), tempStr2)) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + } + catch(DOMException&) + { + fprintf(stderr, "checking testLSExceptions failed at line %i\n", __LINE__); + OK=false; + } + input->release(); domBuilder->release(); @@ -5092,7 +5162,7 @@ bool DOMTest::testElementTraversal() { "\t\td='M25,150 C180,180 290,0 400,140 S420,100 460,90'/>\n" "\t<text id='text1' x='0' y='0' font-size='35' fill='yellow' stroke='orange'\n" "\t\tstroke-width='2' stroke-linejoin='round' font-weight='bold'>\n" - "\t\t<textPath id='textPath1' xlink:href='#path1'>&ent1;&ent2;&ent1;</textPath></text>\n" + "\t\t<textPath id='textPath1' href='#path1'>&ent1;&ent2;&ent1;</textPath></text>\n" "</g>"; MemBufInputSource is((XMLByte*)sXml, strlen(sXml), "bufId"); -- GitLab