1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-21 14:53:44 +03:00

tree: Fix xmlGetNodePath

- Fix quadratic behavior
- Don't truncate names

Fixes #715.
This commit is contained in:
Nick Wellnhofer
2025-06-24 13:02:13 +02:00
parent 22246f21c5
commit ad0f5d27c4
5 changed files with 108 additions and 108 deletions

20
result/scripts/whereis Normal file
View File

@@ -0,0 +1,20 @@
/ > /d:doc
/d:doc/a[1]
/d:doc/b
/d:doc/a[2]
/d:doc/c
/d:doc/a[3]
/d:doc/a[4]
/d:doc/a[4]/e:e[1]
/d:doc/a[4]/e:e[2]
/d:doc/a[4]/b
/d:doc/a[4]/e:e[3]
/d:doc/a[4]/e:e[4]
/d:doc/a[4]/e:e[5]
/d:doc/a[4]/e:e[5]/*[1]
/d:doc/a[4]/e:e[5]/*[2]
/d:doc/a[4]/e:e[5]/*[3]
/d:doc/a[4]/e:e[6]
/d:doc/a[5]
/ > /d:doc/a[4]/e:e[5]/*[3]/@e:attr
/ >

View File

View File

@@ -0,0 +1,2 @@
whereis //*
whereis //@*

18
test/scripts/whereis.xml Normal file
View File

@@ -0,0 +1,18 @@
<d:doc xmlns:d="urn:d" xmlns:e="urn:e">
<a/><b/>
<a/><c/>
<a/>
<a>
<e:e/>
<e:e/><b/>
<e:e/>
<e:e/>
<e:e xmlns="urn:g">
<x/>
<x/>
<x e:attr="val"/>
</e:e>
<e:e/>
</a>
<a/>
</d:doc>

176
tree.c
View File

@@ -4450,60 +4450,68 @@ xmlGetLineNo(const xmlNode *node)
xmlChar *
xmlGetNodePath(const xmlNode *node)
{
const xmlNode *cur, *tmp, *next;
xmlChar *buffer = NULL;
size_t buf_len, len;
xmlChar *buf;
const char *sep;
const char *name;
char nametemp[100];
int occur = 0, generic;
const xmlNode *cur, *tmp;
const xmlNode **nodes = NULL;
xmlChar *ret = NULL;
xmlBuf *buf;
size_t numNodes, i;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
return (NULL);
return(NULL);
buf_len = 500;
buffer = xmlMalloc(buf_len);
if (buffer == NULL)
return (NULL);
buf = xmlMalloc(buf_len);
if (buf == NULL) {
xmlFree(buffer);
return (NULL);
}
buf = xmlBufCreate(50);
if (buf == NULL)
return(NULL);
/*
* Get list of ancestors
*/
numNodes = 0;
for (cur = node; cur != NULL; cur = cur->parent)
numNodes += 1;
if (numNodes > SIZE_MAX / sizeof(nodes[0]))
goto error;
nodes = xmlMalloc(numNodes * sizeof(nodes[0]));
if (nodes == NULL)
goto error;
i = 0;
for (cur = node; cur != NULL && i < numNodes; cur = cur->parent)
nodes[i++] = cur;
/*
* Iterate in reverse to start at root
*/
while (i > 0) {
int occur = 0;
i -= 1;
cur = nodes[i];
buffer[0] = 0;
cur = node;
do {
name = "";
sep = "?";
occur = 0;
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
if (buffer[0] == '/')
break;
sep = "/";
next = NULL;
if (i == 0)
xmlBufCat(buf, BAD_CAST "/");
} else if (cur->type == XML_ELEMENT_NODE) {
generic = 0;
sep = "/";
name = (const char *) cur->name;
int generic = 0;
xmlBufCat(buf, BAD_CAST "/");
if (cur->ns) {
if (cur->ns->prefix != NULL) {
snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
(char *)cur->ns->prefix, (char *)cur->name);
nametemp[sizeof(nametemp) - 1] = 0;
name = nametemp;
xmlBufCat(buf, cur->ns->prefix);
xmlBufCat(buf, BAD_CAST ":");
xmlBufCat(buf, cur->name);
} else {
/*
* We cannot express named elements in the default
* namespace, so use "*".
*/
generic = 1;
name = "*";
xmlBufCat(buf, BAD_CAST "*");
}
} else {
xmlBufCat(buf, cur->name);
}
next = cur->parent;
/*
* Thumbler index computation
@@ -4537,9 +4545,7 @@ xmlGetNodePath(const xmlNode *node)
} else
occur++;
} else if (cur->type == XML_COMMENT_NODE) {
sep = "/";
name = "comment()";
next = cur->parent;
xmlBufCat(buf, BAD_CAST "/comment()");
/*
* Thumbler index computation
@@ -4563,9 +4569,7 @@ xmlGetNodePath(const xmlNode *node)
occur++;
} else if ((cur->type == XML_TEXT_NODE) ||
(cur->type == XML_CDATA_SECTION_NODE)) {
sep = "/";
name = "text()";
next = cur->parent;
xmlBufCat(buf, BAD_CAST "/text()");
/*
* Thumbler index computation
@@ -4595,13 +4599,9 @@ xmlGetNodePath(const xmlNode *node)
} else
occur++;
} else if (cur->type == XML_PI_NODE) {
sep = "/";
snprintf(nametemp, sizeof(nametemp) - 1,
"processing-instruction('%s')", (char *)cur->name);
nametemp[sizeof(nametemp) - 1] = 0;
name = nametemp;
next = cur->parent;
xmlBufCat(buf, BAD_CAST "/processing-instruction('");
xmlBufCat(buf, cur->name);
xmlBufCat(buf, BAD_CAST "')");
/*
* Thumbler index computation
@@ -4627,70 +4627,30 @@ xmlGetNodePath(const xmlNode *node)
occur++;
} else if (cur->type == XML_ATTRIBUTE_NODE) {
sep = "/@";
name = (const char *) (((xmlAttrPtr) cur)->name);
if (cur->ns) {
if (cur->ns->prefix != NULL)
snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
(char *)cur->ns->prefix, (char *)cur->name);
else
snprintf(nametemp, sizeof(nametemp) - 1, "%s",
(char *)cur->name);
nametemp[sizeof(nametemp) - 1] = 0;
name = nametemp;
xmlBufCat(buf, BAD_CAST "/@");
if (cur->ns && cur->ns->prefix != NULL) {
xmlBufCat(buf, cur->ns->prefix);
xmlBufCat(buf, BAD_CAST ":");
}
next = ((xmlAttrPtr) cur)->parent;
xmlBufCat(buf, cur->name);
} else {
xmlFree(buf);
xmlFree(buffer);
return (NULL);
goto error;
}
/*
* Make sure there is enough room
*/
len = strlen((const char *) buffer);
if (buf_len - len < sizeof(nametemp) + 20) {
xmlChar *temp;
int newSize;
if (occur > 0) {
char tmpbuf[30];
if ((buf_len > SIZE_MAX / 2) ||
(2 * buf_len > SIZE_MAX - len - sizeof(nametemp) - 20)) {
xmlFree(buf);
xmlFree(buffer);
return (NULL);
}
newSize = 2 * buf_len + len + sizeof(nametemp) + 20;
temp = xmlRealloc(buffer, newSize);
if (temp == NULL) {
xmlFree(buf);
xmlFree(buffer);
return (NULL);
}
buffer = temp;
temp = xmlRealloc(buf, newSize);
if (temp == NULL) {
xmlFree(buf);
xmlFree(buffer);
return (NULL);
}
buf = temp;
buf_len = newSize;
snprintf(tmpbuf, sizeof(tmpbuf), "[%d]", occur);
xmlBufCat(buf, BAD_CAST tmpbuf);
}
if (occur == 0)
snprintf((char *) buf, buf_len, "%s%s%s",
sep, name, (char *) buffer);
else
snprintf((char *) buf, buf_len, "%s%s[%d]%s",
sep, name, occur, (char *) buffer);
snprintf((char *) buffer, buf_len, "%s", (char *)buf);
cur = next;
} while (cur != NULL);
xmlFree(buf);
return (buffer);
}
ret = xmlBufDetach(buf);
error:
xmlBufFree(buf);
xmlFree(nodes);
return(ret);
}
/**