如何使用XPath匹配以数字结尾的字符串

时间:2018-10-10 14:38:26

标签: java xml xpath java-8

问题是我正在寻找一个XPath表达式,以获取具有属性XXX的节点,这些属性的值像TP *一样,其中星号是数字。 假设我有这个XML文件

<tagA attA="VAL1">text</tagA>
<tagB attB="VAL333">text</tagB>
<tagA attA="VAL2">text</tagA>
<tagA attA="V2">text</tagA>

因此,xpath表达式应该使我所有拥有属性tagA的{​​{1}}都具有模式attrA的值
VAL*:不起作用

请帮忙吗?

3 个答案:

答案 0 :(得分:4)

如果您需要XPath 1.0解决方案,请尝试以下操作:

//tagA[boolean(number(substring-after(@attA, "VAL"))) or number(substring-after(@attA, "VAL")) = 0]

如果@attA不能为"VAL0",那么

//tagA[boolean(number(substring-after(@attA, "VAL")))]

答案 1 :(得分:2)

matches()需要 XPath 2.0 ,但是Java 8中的javax.xml.xpath仅支持XPath 1.0。

此外,matches()的第一个参数是要匹配的字符串。所以,您想要:

//tagA[@attrA[matches(., 'VAL\d')]]

这是在"VAL"的属性值中的任意位置寻找@attrA和一位数字。如果您希望将整个字符串与多个/可选的数字后缀(XPath 2.0)或@jschnasse's answer匹配以获取XPath 1.0解决方案,请参见Andersson's answer中的正则表达式。

答案 2 :(得分:1)

向您的*添加一个量词(+\d,...)。试试

'^VAL\d*$'

正如@ kjhughes所指出的。这不适用于标准Java,因为即使Java 11的当前版本也不支持XPath 2.0。 但是,如果需要XPath 2.0支持,则可以使用Saxon

撒克逊人的例子(它是variant of this answer using 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);
    }
}

打印

<tagA attA="VAL1">text</tagA>

<tagA attA="VAL2">text</tagA>