#3215: XML parser returns item from different element in a array

This commit is contained in:
Günter Obiltschnig 2021-06-15 08:52:58 +02:00
parent 6fda5b590b
commit 73ee047a37
3 changed files with 154 additions and 119 deletions

View File

@ -53,7 +53,7 @@ protected:
void dispatchNodeRemovedFromDocument(); void dispatchNodeRemovedFromDocument();
void dispatchNodeInsertedIntoDocument(); void dispatchNodeInsertedIntoDocument();
static const Node* findNode(XMLString::const_iterator& it, const XMLString::const_iterator& end, const Node* pNode, const NSMap* pNSMap); static const Node* findNode(XMLString::const_iterator& it, const XMLString::const_iterator& end, const Node* pNode, const NSMap* pNSMap, bool& indexBound);
static const Node* findElement(const XMLString& name, const Node* pNode, const NSMap* pNSMap); static const Node* findElement(const XMLString& name, const Node* pNode, const NSMap* pNSMap);
static const Node* findElement(int index, const Node* pNode, const NSMap* pNSMap); static const Node* findElement(int index, const Node* pNode, const NSMap* pNSMap);
static const Node* findElement(const XMLString& attr, const XMLString& value, const Node* pNode, const NSMap* pNSMap); static const Node* findElement(const XMLString& attr, const XMLString& value, const Node* pNode, const NSMap* pNSMap);

View File

@ -311,6 +311,7 @@ bool AbstractContainerNode::hasAttributes() const
Node* AbstractContainerNode::getNodeByPath(const XMLString& path) const Node* AbstractContainerNode::getNodeByPath(const XMLString& path) const
{ {
bool indexBound;
XMLString::const_iterator it = path.begin(); XMLString::const_iterator it = path.begin();
if (it != path.end() && *it == '/') if (it != path.end() && *it == '/')
{ {
@ -327,18 +328,19 @@ Node* AbstractContainerNode::getNodeByPath(const XMLString& path) const
for (unsigned long i = 0; i < length; i++) for (unsigned long i = 0; i < length; i++)
{ {
XMLString::const_iterator beg = it; XMLString::const_iterator beg = it;
const Node* pNode = findNode(beg, path.end(), pList->item(i), 0); const Node* pNode = findNode(beg, path.end(), pList->item(i), 0, indexBound);
if (pNode) return const_cast<Node*>(pNode); if (pNode) return const_cast<Node*>(pNode);
} }
return 0; return 0;
} }
} }
return const_cast<Node*>(findNode(it, path.end(), this, 0)); return const_cast<Node*>(findNode(it, path.end(), this, 0, indexBound));
} }
Node* AbstractContainerNode::getNodeByPathNS(const XMLString& path, const NSMap& nsMap) const Node* AbstractContainerNode::getNodeByPathNS(const XMLString& path, const NSMap& nsMap) const
{ {
bool indexBound;
XMLString::const_iterator it = path.begin(); XMLString::const_iterator it = path.begin();
if (it != path.end() && *it == '/') if (it != path.end() && *it == '/')
{ {
@ -368,19 +370,20 @@ Node* AbstractContainerNode::getNodeByPathNS(const XMLString& path, const NSMap&
for (unsigned long i = 0; i < length; i++) for (unsigned long i = 0; i < length; i++)
{ {
XMLString::const_iterator beg = it; XMLString::const_iterator beg = it;
const Node* pNode = findNode(beg, path.end(), pList->item(i), &nsMap); const Node* pNode = findNode(beg, path.end(), pList->item(i), &nsMap, indexBound);
if (pNode) return const_cast<Node*>(pNode); if (pNode) return const_cast<Node*>(pNode);
} }
} }
return 0; return 0;
} }
} }
return const_cast<Node*>(findNode(it, path.end(), this, &nsMap)); return const_cast<Node*>(findNode(it, path.end(), this, &nsMap, indexBound));
} }
const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const XMLString::const_iterator& end, const Node* pNode, const NSMap* pNSMap) const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const XMLString::const_iterator& end, const Node* pNode, const NSMap* pNSMap, bool& indexBound)
{ {
indexBound = false;
if (pNode && it != end) if (pNode && it != end)
{ {
if (*it == '[') if (*it == '[')
@ -406,7 +409,8 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
while (it != end && *it != ']') value += *it++; while (it != end && *it != ']') value += *it++;
} }
if (it != end) ++it; if (it != end) ++it;
return findNode(it, end, findElement(attr, value, pNode, pNSMap), pNSMap); bool ib;
return findNode(it, end, findElement(attr, value, pNode, pNSMap), pNSMap, ib);
} }
else else
{ {
@ -416,17 +420,19 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
} }
else else
{ {
XMLString index; XMLString xmlIndex;
while (it != end && *it != ']') index += *it++; while (it != end && *it != ']') xmlIndex += *it++;
if (it != end) ++it; if (it != end) ++it;
#ifdef XML_UNICODE_WCHAR_T #ifdef XML_UNICODE_WCHAR_T
std::string idx; std::string index;
Poco::UnicodeConverter::convert(index, idx); Poco::UnicodeConverter::convert(xmlIndex, index);
int i = Poco::NumberParser::parse(idx);
#else
int i = Poco::NumberParser::parse(index); int i = Poco::NumberParser::parse(index);
#else
int i = Poco::NumberParser::parse(xmlIndex);
#endif #endif
return findNode(it, end, findElement(i, pNode, pNSMap), pNSMap); indexBound = true;
bool ib;
return findNode(it, end, findElement(i, pNode, pNSMap), pNSMap, ib);
} }
} }
else else
@ -440,8 +446,9 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
const Node* pElem = findElement(key, pNode->firstChild(), pNSMap); const Node* pElem = findElement(key, pNode->firstChild(), pNSMap);
while (!pFound && pElem) while (!pFound && pElem)
{ {
pFound = findNode(it, end, pElem, pNSMap); bool ib;
if (!pFound) pElem = findElement(key, pElem->nextSibling(), pNSMap); pFound = findNode(it, end, pElem, pNSMap, ib);
if (!pFound) pElem = ib ? nullptr : findElement(key, pElem->nextSibling(), pNSMap);
it = itStart; it = itStart;
} }
return pFound; return pFound;

View File

@ -616,7 +616,7 @@ void ElementTest::testNodeByPath()
<elemA/> <elemA/>
<elemA/> <elemA/>
</elem1> </elem1>
<elem2> <elem2 index="0">
<elemB attr1="value1"/> <elemB attr1="value1"/>
<elemB attr1="value2"/> <elemB attr1="value2"/>
<elemB attr1="value3"/> <elemB attr1="value3"/>
@ -626,8 +626,9 @@ void ElementTest::testNodeByPath()
</elemC> </elemC>
<elemC attr1="value2"/> <elemC attr1="value2"/>
</elem2> </elem2>
<elem2> <elem2 index="1">
<elemB attr1="value4"/> <elemB attr1="value4"/>
<elemD attr1="value1"/>
</elem2> </elem2>
</root> </root>
*/ */
@ -646,6 +647,10 @@ void ElementTest::testNodeByPath()
AutoPtr<Element> pElem25 = pDoc->createElement("elemC"); AutoPtr<Element> pElem25 = pDoc->createElement("elemC");
AutoPtr<Element> pElem3 = pDoc->createElement("elem2"); AutoPtr<Element> pElem3 = pDoc->createElement("elem2");
AutoPtr<Element> pElem31 = pDoc->createElement("elemB"); AutoPtr<Element> pElem31 = pDoc->createElement("elemB");
AutoPtr<Element> pElem32 = pDoc->createElement("elemD");
pElem2->setAttribute("index", "0");
pElem3->setAttribute("index", "1");
pElem21->setAttribute("attr1", "value1"); pElem21->setAttribute("attr1", "value1");
pElem22->setAttribute("attr1", "value2"); pElem22->setAttribute("attr1", "value2");
@ -655,6 +660,7 @@ void ElementTest::testNodeByPath()
pElem25->setAttribute("attr1", "value2"); pElem25->setAttribute("attr1", "value2");
pElem31->setAttribute("attr1", "value4"); pElem31->setAttribute("attr1", "value4");
pElem32->setAttribute("attr1", "value1");
AutoPtr<Element> pElem241 = pDoc->createElement("elemC1"); AutoPtr<Element> pElem241 = pDoc->createElement("elemC1");
AutoPtr<Element> pElem242 = pDoc->createElement("elemC2"); AutoPtr<Element> pElem242 = pDoc->createElement("elemC2");
@ -671,6 +677,7 @@ void ElementTest::testNodeByPath()
pElem2->appendChild(pElem25); pElem2->appendChild(pElem25);
pElem3->appendChild(pElem31); pElem3->appendChild(pElem31);
pElem3->appendChild(pElem32);
pRoot->appendChild(pElem1); pRoot->appendChild(pElem1);
pRoot->appendChild(pElem2); pRoot->appendChild(pElem2);
@ -750,11 +757,32 @@ void ElementTest::testNodeByPath()
pNode = pDoc->getNodeByPath("//[@attr1='value1']"); pNode = pDoc->getNodeByPath("//[@attr1='value1']");
assertTrue (pNode == pElem21); assertTrue (pNode == pElem21);
pNode = pDoc->getNodeByPath("//[@attr1='value4']");
assertTrue (pNode == pElem31);
pNode = pDoc->getNodeByPath("//[@attr1='value2']"); pNode = pDoc->getNodeByPath("//[@attr1='value2']");
assertTrue (pNode == pElem22); assertTrue (pNode == pElem22);
pNode = pRoot->getNodeByPath("/elem2/*[@attr1='value2']"); pNode = pRoot->getNodeByPath("/elem2/*[@attr1='value2']");
assertTrue (pNode == pElem22); assertTrue (pNode == pElem22);
pNode = pDoc->getNodeByPath("/root/elem2[0]/elemC");
assertTrue (pNode == pElem24);
pNode = pDoc->getNodeByPath("/root/elem2[1]/elemC");
assertTrue (pNode == 0);
pNode = pDoc->getNodeByPath("/root/elem2[0]/elemD");
assertTrue (pNode == 0);
pNode = pDoc->getNodeByPath("/root/elem2[1]/elemD");
assertTrue (pNode == pElem32);
pNode = pDoc->getNodeByPath("/root/elem2[@index=0]/elemD");
assertTrue (pNode == 0);
pNode = pDoc->getNodeByPath("/root/elem2[@index=1]/elemD");
assertTrue (pNode == pElem32);
} }