简体   繁体   中英

Reading multiple XML attributes with xpath

So say I have something like this:

<info>
    <collectorKey id="key"/>
    <credentials user="user" password="password"/>
    <Infos>
        <dummyInfo>
            <infoSource temp="N/A">               
                <tags>
                    <tag id="1" value="example"/>
                    <tag id="2" value="example"/>
                    <tag id="3" value="example"/>
                    <tag id="4" value="example"/>
                    <tag id="5" value="example"/>
                    <tag id="6" value="example"/>
                    <tag id="7" value="example"/>
                </tags>
            </infoSource>
        </dummyInfo>
    </Infos>
    <Infos>
        <dummyInfo>
            <infoSource temp="N/A">               
                <tags>
                    <tag id="1" value="example"/>
                    <tag id="2" value="example"/>
                    <tag id="3" value="example"/>
                    <tag id="4" value="example"/>
                    <tag id="5" value="example"/>
                    <tag id="6" value="example"/>
                    <tag id="7" value="example"/>
                </tags>
            </infoSource>
        </dummyInfo>
    </Infos>
</info>

and I want grab every tag attribute with the ID 2 and get the value for that tag. Right now I have some long winded code to do it and it does not seem very practical. I'd like to convert it to use xpath if possible I was wondering how this would be done. I threw some skeleton code together but it's not garbing my tag values with 2. I presume some loop would need to be added along with some changes.

Something like:

try {
        ClassLoader classLoader = getClass().getClassLoader();
        File configProdXML = new File(classLoader.getResource("files/config-prod.xml").getFile());

        //parse it using a docbuilder
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = null;
        dBuilder = dbFactory.newDocumentBuilder();
        Document parsedConfig = dBuilder.parse(configProdXML);

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("/tags/tags/@id=2/text()");

        System.out.println(expr.toString());

side note. Would xpath be the most practical thing with for this?

Yes, XPath is ideal for this:

XPathExpression expr = xpath.compile("//tags/tag[@id=2]/@example");

Some explanation:

  • The two slashes in //tags means all <tags> elements, at any level, anywhere in the document.
  • tag[@id=2] means <tag> elements, but with a predicate that restricts which elements qualify.

Normally, it isn't necessary to call XPath.compile directly, unless you plan to apply the same XPath to many different sources. You can just call an evaluate method directly:

NodeList values = (NodeList)
    xpath.evaluate("//tags/tag[@id=2]/@example", parsedConfig,
        XPathConstants.NODESET);

CAUTION: Never call URL.getFile(). It does not convert a URL into a valid file name—it just returns the portion of the URL after the host and port, which may contain percent-escapes for the many characters which are not allowed to appear in URLs. Also, the URL returned by Class.getResource or ClassLoader.getResource is not guaranteed to point to a file at all; in particular, if you ever try to run from a .jar file, you will not get a file: URL.

Fortunately, you don't need a file. You don't even need to parse a Document. You can just pass an InputStream directly to your XPath:

try (InputStream config = getClass().getResourceAsStream("/files/config-prod.xml")) {

    NodeList values = (NodeList)
        xpath.evaluate("//tags/tag[@id=2]/@example", new InputSource(config),
            XPathConstants.NODESET);

    int count = values.getLength();
    for (int i = 0; i < count; i++) {
        String value = values.item(i).getNodeValue();
        System.out.println("Found value \"" + value + "\"");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM