The issue is that I'm looking to construct an XPath expression to get nodes having attributes XXX having values like TP* where the star is a number. Suppose I have this XML file
问题是,我正在构建一个XPath表达式,以获取具有属性XXX的节点,其值为TP *,其中星号是数字。假设我有这个XML文件
<tagA attA="VAL1">text</tagA>
<tagB attB="VAL333">text</tagB>
<tagA attA="VAL2">text</tagA>
<tagA attA="V2">text</tagA>
So the xpath expression should get me all tagA
having attribute attrA
with values with the pattern VAL*
//tagA[@attrA[matches('VAL\d')]]
: is not working
所以xpath表达式应该让我所有tagA都具有属性attrA,其值为模式VAL * // tagA [@attrA [matches('VAL \ d')]]:不起作用
Any help please ?
有什么帮助吗?
3 个解决方案
#1
4
If you need XPath 1.0 solution, try below:
如果您需要XPath 1.0解决方案,请尝试以下操作:
//tagA[boolean(number(substring-after(@attA, "VAL"))) or number(substring-after(@attA, "VAL")) = 0]
If @attA
cannot be "VAL0"
, then just
如果@attA不能是“VAL0”,那么就是
//tagA[boolean(number(substring-after(@attA, "VAL")))]
#2
2
matches()
requires XPath 2.0, but javax.xml.xpath in Java 8 supports only XPath 1.0.
matches()需要XPath 2.0,但Java 8中的javax.xml.xpath仅支持XPath 1.0。
Furthermore, the first argument of matches()
is the string to match. So, you'd want:
此外,matches()的第一个参数是要匹配的字符串。所以,你想要:
//tagA[@attrA[matches(., 'VAL\d')]]
This is looking for "VAL"
plus a single digit anywhere in the attribute value of @attrA
. See the regex in @jschnasse's answer if you wish to match the entire string with multiple/optional digit suffixes (XPath 2.0) or Andersson's answer for an XPath 1.0 solution.
这是在@attrA的属性值中的任何地方寻找“VAL”加上一个数字。如果您希望将整个字符串与多个/可选数字后缀(XPath 2.0)或Andersson对XPath 1.0解决方案的答案进行匹配,请参阅@ jschnasse的答案中的正则表达式。
#3
1
Add a quantifier (*
,+
,...) to your \d
. Try
在你的\ d中添加一个量词(*,+,...)。尝试
'^VAL\d*$'
As @kjhughes has pointed out. This will not work with standard Java, because even current version of Java 11 does not support XPath 2.0. You can however use Saxon if you need XPath 2.0 support.
正如@kjhughes指出的那样。这不适用于标准Java,因为即使当前版本的Java 11也不支持XPath 2.0。但是,如果需要XPath 2.0支持,可以使用Saxon。
Saxon Example (It is a variant of this answer using javax.xml)
Saxon示例(这是使用javax.xml的这个答案的变体)
Processor processor = new Processor(false);
@Test
public void xpathWithSaxon() {
String xml = "<root><tagA attA=\"VAL1\">text</tagA>\n" + "<tagB attB=\"VAL333\">text</tagB>\n"
+ "<tagA attA=\"VAL2\">text</tagA>\n" + "<tagA attA=\"V2\">text</tagA>\n" + "</root>";
try (InputStream in = new ByteArrayInputStream(xml.getBytes("utf-8"));) {
processFilteredXmlWith(in, "//root/tagA[matches(@attA,'^VAL\\d*$')]", (node) -> {
printItem(node, System.out);
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void printItem(XdmItem node, PrintStream out) {
out.println(node);
}
public void processFilteredXmlWith(InputStream in, String xpath, Consumer<XdmItem> process) {
XdmNode doc = readXmlWith(in);
XdmValue list = filterNodesByXPathWith(doc, xpath);
list.forEach((node) -> {
process.accept(node);
});
}
private XdmNode readXmlWith(InputStream xmlin) {
try {
return processor.newDocumentBuilder().build(new StreamSource(xmlin));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private XdmValue filterNodesByXPathWith(XdmNode doc, String xpathExpr) {
try {
return processor.newXPathCompiler().evaluate(xpathExpr, doc);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Prints
<tagA attA="VAL1">text</tagA>
<tagA attA="VAL2">text</tagA>
#1
4
If you need XPath 1.0 solution, try below:
如果您需要XPath 1.0解决方案,请尝试以下操作:
//tagA[boolean(number(substring-after(@attA, "VAL"))) or number(substring-after(@attA, "VAL")) = 0]
If @attA
cannot be "VAL0"
, then just
如果@attA不能是“VAL0”,那么就是
//tagA[boolean(number(substring-after(@attA, "VAL")))]
#2
2
matches()
requires XPath 2.0, but javax.xml.xpath in Java 8 supports only XPath 1.0.
matches()需要XPath 2.0,但Java 8中的javax.xml.xpath仅支持XPath 1.0。
Furthermore, the first argument of matches()
is the string to match. So, you'd want:
此外,matches()的第一个参数是要匹配的字符串。所以,你想要:
//tagA[@attrA[matches(., 'VAL\d')]]
This is looking for "VAL"
plus a single digit anywhere in the attribute value of @attrA
. See the regex in @jschnasse's answer if you wish to match the entire string with multiple/optional digit suffixes (XPath 2.0) or Andersson's answer for an XPath 1.0 solution.
这是在@attrA的属性值中的任何地方寻找“VAL”加上一个数字。如果您希望将整个字符串与多个/可选数字后缀(XPath 2.0)或Andersson对XPath 1.0解决方案的答案进行匹配,请参阅@ jschnasse的答案中的正则表达式。
#3
1
Add a quantifier (*
,+
,...) to your \d
. Try
在你的\ d中添加一个量词(*,+,...)。尝试
'^VAL\d*$'
As @kjhughes has pointed out. This will not work with standard Java, because even current version of Java 11 does not support XPath 2.0. You can however use Saxon if you need XPath 2.0 support.
正如@kjhughes指出的那样。这不适用于标准Java,因为即使当前版本的Java 11也不支持XPath 2.0。但是,如果需要XPath 2.0支持,可以使用Saxon。
Saxon Example (It is a variant of this answer using javax.xml)
Saxon示例(这是使用javax.xml的这个答案的变体)
Processor processor = new Processor(false);
@Test
public void xpathWithSaxon() {
String xml = "<root><tagA attA=\"VAL1\">text</tagA>\n" + "<tagB attB=\"VAL333\">text</tagB>\n"
+ "<tagA attA=\"VAL2\">text</tagA>\n" + "<tagA attA=\"V2\">text</tagA>\n" + "</root>";
try (InputStream in = new ByteArrayInputStream(xml.getBytes("utf-8"));) {
processFilteredXmlWith(in, "//root/tagA[matches(@attA,'^VAL\\d*$')]", (node) -> {
printItem(node, System.out);
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void printItem(XdmItem node, PrintStream out) {
out.println(node);
}
public void processFilteredXmlWith(InputStream in, String xpath, Consumer<XdmItem> process) {
XdmNode doc = readXmlWith(in);
XdmValue list = filterNodesByXPathWith(doc, xpath);
list.forEach((node) -> {
process.accept(node);
});
}
private XdmNode readXmlWith(InputStream xmlin) {
try {
return processor.newDocumentBuilder().build(new StreamSource(xmlin));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private XdmValue filterNodesByXPathWith(XdmNode doc, String xpathExpr) {
try {
return processor.newXPathCompiler().evaluate(xpathExpr, doc);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Prints
<tagA attA="VAL1">text</tagA>
<tagA attA="VAL2">text</tagA>