根据元素值获取祖先节点的 Xpath 查询 [英] Xpath query to get the ancester nodes based on element value
问题描述
我试图找到所有符合以下两条规则的元素名称.
1.元素应该具有
2.如果两个或多个元素在层次结构中具有
(例如: 和
> 两者都有
) 然后只需要打印父节点名称(即 在这种情况下).
所以下面的xml需要的结果是:
<块引用>b , y , p
当我使用 query = (//set[contains(.,'erase')])[1]
时,结果集中只得到节点 b
.
当我使用 query =//set[contains(.,'erase')]
时,我得到结果集中的所有节点列表 b,d,y,p
.>
谁能帮我找到导致 nodeList b
, y
和 p
的查询.
这是我使用的java代码片段.
XPath xpath = factory.newXPath();String query = "//set[contains(.,'erase')]";XPathExpression expr=null;尝试 {expr = xpath.compile(query);} catch (XPathExpressionException e) {//TODO 自动生成的 catch 块e.printStackTrace();}对象结果 = 空;尝试 {结果 = expr.evaluate(doc, XPathConstants.NODESET);} catch (XPathExpressionException e) {e.printStackTrace();}NodeList 节点 = (NodeList) 结果;for (int i = 0; i
输出:
a.ba.b.da.e.ya.e.z.p
谁能帮我找出只导致 a.b、a.e.y 和 a.e.z.p
的查询如果您需要更多详细信息,请告诉我.或任何其他用例.
一个精确选择所需元素的表达式是:
//*[set[.= '擦除' 而不是(节点()[2])]和不是(祖先::*[放[.= '擦除' 而不是(节点()[2])]])]
基于 XSLT 的验证:
<xsl:output omit-xml-declaration="yes" indent="yes"/><xsl:strip-space elements="*"/><xsl:template match="/"><xsl:for-each select="///*[set[. = 'erase' and not(node()[2])]和不是(祖先::*[放[.= '擦除' 而不是(节点()[2])]])]"><xsl:value-of select="name()"/><xsl:text>
</xsl:text></xsl:for-each></xsl:模板></xsl:stylesheet>
这种转换,当应用于由 Sean B. Durkin 提供的 XML 文档时:
<b><set>擦除</set><设置><a/>擦除</set><d><set>擦除</set></d></b><c><x></x></c><e><y><set>擦除</set><q></q></y><z><p><set>擦除</set></p></z></e></a>
评估上面的 XPath 表达式并输出所选元素的名称——产生想要的、正确的结果:
b是磷
请注意以下两种表达方式是非常不正确的:
*[set[text()='erase']][not(ancestor::*[set[text()='erase']])]
或者:
*[set[text()='erase']][ancestor::*[set[text()!='erase']]]
这两个表达式有不止一个问题:
它们是相对表达式,无论它们应用于哪个初始上下文,它们都无法在具有未定义深度和结构的层次结构中选择所有想要的元素.
set[text()='erase']
不仅选择表单的一个元素:
...
erase
还有表单元素:
xyz<a/>擦除</set>
.3.同样:
set[text()!='erase']
选择表单元素:
xyz<a/>擦除</set>
I am trying to find all the element names which follow the below two rules.
1. elements should have the <set>erase</set>
2. if two or more elements have the <set>erase</set>
in hierarchy (Ex: <b>
and <d>
both have <set>erase</set>
) then only the parent node name has to be printed(ie <b>
in this case).
So the required result for below xml needs to be :
b , y , p
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a>
<b>
<set>erase</set>
<d>
<set>erase</set>
</d>
</b>
<c>
<x>
</x>
</c>
<e>
<y>
<set>erase</set>
<q>
</q>
</y>
<z>
<p>
<set>erase</set>
</p>
</z>
</e>
</a>
When I use the query = (//set[contains(.,'erase')])[1]
I get only node b
in result set.
When I use the query = //set[contains(.,'erase')]
I get all nodesList b,d,y,p
in result set.
Can anyone help me find the query to result in nodeList b
, y
and p
.
Here is the java code snippet I used.
XPath xpath = factory.newXPath();
String query = "//set[contains(.,'erase')]";
XPathExpression expr=null;
try {
expr = xpath.compile(query);
} catch (XPathExpressionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object result = null;
try {
result = expr.evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
String x = "";
Node n = nodes.item(i).getParentNode();
x=n.getNodeName();
while(!n.getNodeName().equalsIgnoreCase(request.getClass().getSimpleName())){
if ((n = n.getParentNode())!=null){
x=n.getNodeName()+"."+x;
}
}
System.out.println("Path: "+x);
output:
a.b
a.b.d
a.e.y
a.e.z.p
Could anyone help me figure out the query which results in only a.b , a.e.y and a.e.z.p
Let me know if you need more details. or any other use-case.
One expression that selects exactly the wanted elements is:
//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]
XSLT - based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:for-each select=
"//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]">
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This transformation, when applied on the provided by Sean B. Durkin XML document:
<a>
<b>
<set>erase</set>
<set>
<a/>erase
</set>
<d>
<set>erase</set>
</d>
</b>
<c>
<x> </x>
</c>
<e>
<y>
<set>erase</set>
<q> </q>
</y>
<z>
<p>
<set>erase</set>
</p>
</z>
</e>
</a>
evaluates the XPath expression above and outputs the names of the selected elements -- the wanted, correct result is produced:
b
y
p
Do note that the following two expressions are quite incorrect:
*[set[text()='erase']][not(ancestor::*[set[text()='erase']])]
Or:
*[set[text()='erase']][ancestor::*[set[text()!='erase']]]
These two expressions suffer from more than one problem:
They are relative expressions and regardless with which initial context they are applied, they cannot select all wanted elements in an hierarchy with undefined depth and structure.
set[text()='erase']
selects not only an element of the form:
...
<set>erase</set>
but also elements of the form:
<set>
xyz
<a/>erase</set>
.3. Similarly:
set[text()!='erase']
selects elements of the form:
<set>
xyz
<a/>erase</set>
这篇关于根据元素值获取祖先节点的 Xpath 查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!