mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-03 01:54:47 +02:00
fixed GH #1826: XPath query error
This commit is contained in:
parent
f8b7681f78
commit
66a7fc6652
@ -64,6 +64,8 @@ protected:
|
|||||||
static bool namesAreEqual(const Node* pNode1, const Node* pNode2, const NSMap* pNSMap);
|
static bool namesAreEqual(const Node* pNode1, const Node* pNode2, const NSMap* pNSMap);
|
||||||
static bool namesAreEqual(const Node* pNode, const XMLString& name, const NSMap* pNSMap);
|
static bool namesAreEqual(const Node* pNode, const XMLString& name, const NSMap* pNSMap);
|
||||||
|
|
||||||
|
static const XMLString WILDCARD;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractNode* _pFirstChild;
|
AbstractNode* _pFirstChild;
|
||||||
|
|
||||||
|
@ -29,6 +29,9 @@ namespace Poco {
|
|||||||
namespace XML {
|
namespace XML {
|
||||||
|
|
||||||
|
|
||||||
|
const XMLString AbstractContainerNode::WILDCARD(toXMLString("*"));
|
||||||
|
|
||||||
|
|
||||||
AbstractContainerNode::AbstractContainerNode(Document* pOwnerDocument):
|
AbstractContainerNode::AbstractContainerNode(Document* pOwnerDocument):
|
||||||
AbstractNode(pOwnerDocument),
|
AbstractNode(pOwnerDocument),
|
||||||
_pFirstChild(0)
|
_pFirstChild(0)
|
||||||
@ -320,7 +323,7 @@ Node* AbstractContainerNode::getNodeByPath(const XMLString& path) const
|
|||||||
XMLString name;
|
XMLString name;
|
||||||
while (it != path.end() && *it != '/' && *it != '@' && *it != '[') name += *it++;
|
while (it != path.end() && *it != '/' && *it != '@' && *it != '[') name += *it++;
|
||||||
if (it != path.end() && *it == '/') ++it;
|
if (it != path.end() && *it == '/') ++it;
|
||||||
if (name.empty()) name += '*';
|
if (name.empty()) name = WILDCARD;
|
||||||
AutoPtr<ElementsByTagNameList> pList = new ElementsByTagNameList(this, name);
|
AutoPtr<ElementsByTagNameList> pList = new ElementsByTagNameList(this, name);
|
||||||
unsigned long length = pList->length();
|
unsigned long length = pList->length();
|
||||||
for (unsigned long i = 0; i < length; i++)
|
for (unsigned long i = 0; i < length; i++)
|
||||||
@ -353,8 +356,8 @@ Node* AbstractContainerNode::getNodeByPathNS(const XMLString& path, const NSMap&
|
|||||||
bool nameOK = true;
|
bool nameOK = true;
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
{
|
{
|
||||||
namespaceURI += '*';
|
namespaceURI = WILDCARD;
|
||||||
localName += '*';
|
localName = WILDCARD;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -421,10 +424,11 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
|
|||||||
#ifdef XML_UNICODE_WCHAR_T
|
#ifdef XML_UNICODE_WCHAR_T
|
||||||
std::string idx;
|
std::string idx;
|
||||||
Poco::UnicodeConverter::convert(index, idx);
|
Poco::UnicodeConverter::convert(index, idx);
|
||||||
return findNode(it, end, findElement(Poco::NumberParser::parse(idx), pNode, pNSMap), pNSMap);
|
int i = Poco::NumberParser::parse(idx);
|
||||||
#else
|
#else
|
||||||
return findNode(it, end, findElement(Poco::NumberParser::parse(index), pNode, pNSMap), pNSMap);
|
int i = Poco::NumberParser::parse(index);
|
||||||
#endif
|
#endif
|
||||||
|
return findNode(it, end, findElement(i, pNode, pNSMap), pNSMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -432,7 +436,17 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
|
|||||||
while (it != end && *it == '/') ++it;
|
while (it != end && *it == '/') ++it;
|
||||||
XMLString key;
|
XMLString key;
|
||||||
while (it != end && *it != '/' && *it != '[') key += *it++;
|
while (it != end && *it != '/' && *it != '[') key += *it++;
|
||||||
return findNode(it, end, findElement(key, pNode, pNSMap), pNSMap);
|
|
||||||
|
XMLString::const_iterator itStart(it);
|
||||||
|
const Node* pFound = 0;
|
||||||
|
const Node* pElem = findElement(key, pNode->firstChild(), pNSMap);
|
||||||
|
while (!pFound && pElem)
|
||||||
|
{
|
||||||
|
pFound = findNode(it, end, pElem, pNSMap);
|
||||||
|
if (!pFound) pElem = findElement(key, pElem->nextSibling(), pNSMap);
|
||||||
|
it = itStart;
|
||||||
|
}
|
||||||
|
return pFound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return pNode;
|
else return pNode;
|
||||||
@ -441,12 +455,11 @@ const Node* AbstractContainerNode::findNode(XMLString::const_iterator& it, const
|
|||||||
|
|
||||||
const Node* AbstractContainerNode::findElement(const XMLString& name, const Node* pNode, const NSMap* pNSMap)
|
const Node* AbstractContainerNode::findElement(const XMLString& name, const Node* pNode, const NSMap* pNSMap)
|
||||||
{
|
{
|
||||||
Node* pChild = pNode->firstChild();
|
while (pNode)
|
||||||
while (pChild)
|
|
||||||
{
|
{
|
||||||
if (pChild->nodeType() == Node::ELEMENT_NODE && namesAreEqual(pChild, name, pNSMap))
|
if (pNode->nodeType() == Node::ELEMENT_NODE && namesAreEqual(pNode, name, pNSMap))
|
||||||
return pChild;
|
return pNode;
|
||||||
pChild = pChild->nextSibling();
|
pNode = pNode->nextSibling();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -542,15 +555,19 @@ bool AbstractContainerNode::namesAreEqual(const Node* pNode, const XMLString& na
|
|||||||
{
|
{
|
||||||
XMLString namespaceURI;
|
XMLString namespaceURI;
|
||||||
XMLString localName;
|
XMLString localName;
|
||||||
if (pNSMap->processName(name, namespaceURI, localName, false))
|
if (name == WILDCARD)
|
||||||
{
|
{
|
||||||
return pNode->namespaceURI() == namespaceURI && pNode->localName() == localName;
|
return true;
|
||||||
|
}
|
||||||
|
else if (pNSMap->processName(name, namespaceURI, localName, false))
|
||||||
|
{
|
||||||
|
return (pNode->namespaceURI() == namespaceURI || namespaceURI == WILDCARD) && (pNode->localName() == localName || localName == WILDCARD);
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return pNode->nodeName() == name;
|
return pNode->nodeName() == name || name == WILDCARD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,6 +628,9 @@ void ElementTest::testNodeByPath()
|
|||||||
</elemC>
|
</elemC>
|
||||||
<elemC attr1="value2"/>
|
<elemC attr1="value2"/>
|
||||||
</elem2>
|
</elem2>
|
||||||
|
<elem2>
|
||||||
|
<elemB attr1="value4"/>
|
||||||
|
</elem2>
|
||||||
</root>
|
</root>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -643,6 +646,8 @@ void ElementTest::testNodeByPath()
|
|||||||
AutoPtr<Element> pElem23 = pDoc->createElement("elemB");
|
AutoPtr<Element> pElem23 = pDoc->createElement("elemB");
|
||||||
AutoPtr<Element> pElem24 = pDoc->createElement("elemC");
|
AutoPtr<Element> pElem24 = pDoc->createElement("elemC");
|
||||||
AutoPtr<Element> pElem25 = pDoc->createElement("elemC");
|
AutoPtr<Element> pElem25 = pDoc->createElement("elemC");
|
||||||
|
AutoPtr<Element> pElem3 = pDoc->createElement("elem2");
|
||||||
|
AutoPtr<Element> pElem31 = pDoc->createElement("elemB");
|
||||||
|
|
||||||
pElem21->setAttribute("attr1", "value1");
|
pElem21->setAttribute("attr1", "value1");
|
||||||
pElem22->setAttribute("attr1", "value2");
|
pElem22->setAttribute("attr1", "value2");
|
||||||
@ -651,6 +656,8 @@ void ElementTest::testNodeByPath()
|
|||||||
pElem24->setAttribute("attr1", "value1");
|
pElem24->setAttribute("attr1", "value1");
|
||||||
pElem25->setAttribute("attr1", "value2");
|
pElem25->setAttribute("attr1", "value2");
|
||||||
|
|
||||||
|
pElem31->setAttribute("attr1", "value4");
|
||||||
|
|
||||||
AutoPtr<Element> pElem241 = pDoc->createElement("elemC1");
|
AutoPtr<Element> pElem241 = pDoc->createElement("elemC1");
|
||||||
AutoPtr<Element> pElem242 = pDoc->createElement("elemC2");
|
AutoPtr<Element> pElem242 = pDoc->createElement("elemC2");
|
||||||
pElem241->setAttribute("attr1", "value1");
|
pElem241->setAttribute("attr1", "value1");
|
||||||
@ -665,8 +672,11 @@ void ElementTest::testNodeByPath()
|
|||||||
pElem2->appendChild(pElem24);
|
pElem2->appendChild(pElem24);
|
||||||
pElem2->appendChild(pElem25);
|
pElem2->appendChild(pElem25);
|
||||||
|
|
||||||
|
pElem3->appendChild(pElem31);
|
||||||
|
|
||||||
pRoot->appendChild(pElem1);
|
pRoot->appendChild(pElem1);
|
||||||
pRoot->appendChild(pElem2);
|
pRoot->appendChild(pElem2);
|
||||||
|
pRoot->appendChild(pElem3);
|
||||||
|
|
||||||
pDoc->appendChild(pRoot);
|
pDoc->appendChild(pRoot);
|
||||||
|
|
||||||
@ -734,6 +744,9 @@ void ElementTest::testNodeByPath()
|
|||||||
assert (pNode == pElem23);
|
assert (pNode == pElem23);
|
||||||
|
|
||||||
pNode = pDoc->getNodeByPath("//elemB[@attr1='value4']");
|
pNode = pDoc->getNodeByPath("//elemB[@attr1='value4']");
|
||||||
|
assert (pNode == pElem31);
|
||||||
|
|
||||||
|
pNode = pDoc->getNodeByPath("//elemB[@attr1='value5']");
|
||||||
assert (pNode == 0);
|
assert (pNode == 0);
|
||||||
|
|
||||||
pNode = pDoc->getNodeByPath("//[@attr1='value1']");
|
pNode = pDoc->getNodeByPath("//[@attr1='value1']");
|
||||||
@ -741,6 +754,9 @@ void ElementTest::testNodeByPath()
|
|||||||
|
|
||||||
pNode = pDoc->getNodeByPath("//[@attr1='value2']");
|
pNode = pDoc->getNodeByPath("//[@attr1='value2']");
|
||||||
assert (pNode == pElem22);
|
assert (pNode == pElem22);
|
||||||
|
|
||||||
|
pNode = pRoot->getNodeByPath("/elem2/*[@attr1='value2']");
|
||||||
|
assert (pNode == pElem22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -762,6 +778,9 @@ void ElementTest::testNodeByPathNS()
|
|||||||
</ns2:elemC>
|
</ns2:elemC>
|
||||||
<ns2:elemC ns2:attr1="value2" xmlns:ns2="urn:ns2"/>
|
<ns2:elemC ns2:attr1="value2" xmlns:ns2="urn:ns2"/>
|
||||||
</ns1:elem2>
|
</ns1:elem2>
|
||||||
|
<ns1:elem2>
|
||||||
|
<ns2:elemB ns2:attr1="value4" xmlns:ns2="urn:ns2"/>
|
||||||
|
</ns1:elem2>
|
||||||
</ns1:root>
|
</ns1:root>
|
||||||
*/
|
*/
|
||||||
AutoPtr<Document> pDoc = new Document;
|
AutoPtr<Document> pDoc = new Document;
|
||||||
@ -776,10 +795,13 @@ void ElementTest::testNodeByPathNS()
|
|||||||
AutoPtr<Element> pElem23 = pDoc->createElementNS("urn:ns2", "ns2:elemB");
|
AutoPtr<Element> pElem23 = pDoc->createElementNS("urn:ns2", "ns2:elemB");
|
||||||
AutoPtr<Element> pElem24 = pDoc->createElementNS("urn:ns2", "ns2:elemC");
|
AutoPtr<Element> pElem24 = pDoc->createElementNS("urn:ns2", "ns2:elemC");
|
||||||
AutoPtr<Element> pElem25 = pDoc->createElementNS("urn:ns2", "ns2:elemC");
|
AutoPtr<Element> pElem25 = pDoc->createElementNS("urn:ns2", "ns2:elemC");
|
||||||
|
AutoPtr<Element> pElem3 = pDoc->createElementNS("urn:ns1", "ns1:elem2");
|
||||||
|
AutoPtr<Element> pElem31 = pDoc->createElementNS("urn:ns2", "ns2:elemB");
|
||||||
|
|
||||||
pElem21->setAttributeNS("urn:ns2", "ns2:attr1", "value1");
|
pElem21->setAttributeNS("urn:ns2", "ns2:attr1", "value1");
|
||||||
pElem22->setAttributeNS("urn:ns2", "ns2:attr1", "value2");
|
pElem22->setAttributeNS("urn:ns2", "ns2:attr1", "value2");
|
||||||
pElem23->setAttributeNS("urn:ns2", "ns2:attr1", "value3");
|
pElem23->setAttributeNS("urn:ns2", "ns2:attr1", "value3");
|
||||||
|
pElem31->setAttributeNS("urn:ns2", "ns2:attr1", "value4");
|
||||||
|
|
||||||
pElem24->setAttributeNS("urn:ns2", "ns2:attr1", "value1");
|
pElem24->setAttributeNS("urn:ns2", "ns2:attr1", "value1");
|
||||||
pElem25->setAttributeNS("urn:ns2", "ns2:attr1", "value2");
|
pElem25->setAttributeNS("urn:ns2", "ns2:attr1", "value2");
|
||||||
@ -797,9 +819,11 @@ void ElementTest::testNodeByPathNS()
|
|||||||
pElem2->appendChild(pElem23);
|
pElem2->appendChild(pElem23);
|
||||||
pElem2->appendChild(pElem24);
|
pElem2->appendChild(pElem24);
|
||||||
pElem2->appendChild(pElem25);
|
pElem2->appendChild(pElem25);
|
||||||
|
pElem3->appendChild(pElem31);
|
||||||
|
|
||||||
pRoot->appendChild(pElem1);
|
pRoot->appendChild(pElem1);
|
||||||
pRoot->appendChild(pElem2);
|
pRoot->appendChild(pElem2);
|
||||||
|
pRoot->appendChild(pElem3);
|
||||||
|
|
||||||
pDoc->appendChild(pRoot);
|
pDoc->appendChild(pRoot);
|
||||||
|
|
||||||
@ -874,6 +898,9 @@ void ElementTest::testNodeByPathNS()
|
|||||||
assert (pNode == pElem23);
|
assert (pNode == pElem23);
|
||||||
|
|
||||||
pNode = pDoc->getNodeByPathNS("//NS2:elemB[@NS2:attr1='value4']", nsMap);
|
pNode = pDoc->getNodeByPathNS("//NS2:elemB[@NS2:attr1='value4']", nsMap);
|
||||||
|
assert (pNode == pElem31);
|
||||||
|
|
||||||
|
pNode = pDoc->getNodeByPathNS("//NS2:elemB[@NS2:attr1='value5']", nsMap);
|
||||||
assert (pNode == 0);
|
assert (pNode == 0);
|
||||||
|
|
||||||
pNode = pDoc->getNodeByPathNS("//[@NS2:attr1='value1']", nsMap);
|
pNode = pDoc->getNodeByPathNS("//[@NS2:attr1='value1']", nsMap);
|
||||||
@ -881,6 +908,15 @@ void ElementTest::testNodeByPathNS()
|
|||||||
|
|
||||||
pNode = pDoc->getNodeByPathNS("//[@NS2:attr1='value2']", nsMap);
|
pNode = pDoc->getNodeByPathNS("//[@NS2:attr1='value2']", nsMap);
|
||||||
assert (pNode == pElem22);
|
assert (pNode == pElem22);
|
||||||
|
|
||||||
|
pNode = pRoot->getNodeByPathNS("/ns1:elem2/*[@NS2:attr1='value2']", nsMap);
|
||||||
|
assert (pNode == pElem22);
|
||||||
|
|
||||||
|
pNode = pRoot->getNodeByPathNS("/ns1:elem2/NS2:*[@NS2:attr1='value2']", nsMap);
|
||||||
|
assert (pNode == pElem22);
|
||||||
|
|
||||||
|
pNode = pRoot->getNodeByPathNS("/ns1:elem2/ns1:*[@NS2:attr1='value2']", nsMap);
|
||||||
|
assert (pNode == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user