XPath and Java with Repeated Tags

谁都会走 提交于 2020-01-05 07:14:11

问题


I'm having some trouble parsing an XML file in Java. The file takes the form:

<root>
  <thing>
    <name>Thing1</name>
    <property>
      <name>Property1</name>
    </property>
    ...
  </thing>
  ...
</root>

Ultimately, I would like to convert this file into a list of Thing objects, which will have a String name (Thing1) and a list of Property objects, which will each also have a name (Property1).

I've been trying to use xpaths to get this data out, but when I try to get just the name for 'thing', it gives me all of the names that appear in 'thing', including those of the 'property's. My code is:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(filename);
XPath xpath = XPathFactory.newInstance().newXPath();


XPathExpression thingExpr = xpath.compile("//thing");
NodeList things = (NodeList)thingExpr.evaluate(dom, XPathConstants.NODESET);
for(int count = 0; count < things.getLength(); count++)
{
    Element thing = (Element)things.item(count);
    XPathExpression nameExpr = xpath.compile(".//name/text()");
    NodeList name = (NodeList) nameExpr.evaluate(thing, XPathConstants.NODESET);
    for(int i = 0; i < name.getLength(); i++)
    {
        System.out.println(name.item(i).getNodeValue());    
    }
}

Can anyone help? Thanks in advance!


回答1:


You could try something like...

public class TestXPath {

    public static void main(String[] args) {
        String xml =
                        "<root>\n"
                        + "    <thing>\n"
                        + "        <name>Thing1</name>\n"
                        + "        <property>\n"
                        + "            <name>Property1</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property2</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property3</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property4</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property5</name>\n"
                        + "        </property>\n"
                        + "    </thing>/n"
                        + "    <NoAThin>\n"
                        + "        <name>Thing2</name>\n"
                        + "        <property>\n"
                        + "            <name>Property1</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property2</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property3</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property4</name>\n"
                        + "        </property>\n"
                        + "        <property>\n"
                        + "            <name>Property5</name>\n"
                        + "        </property>\n"
                        + "    </NoAThin>/n"
                        + "</root>";

        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
            Document dom = db.parse(bais);
            XPath xpath = XPathFactory.newInstance().newXPath();

            // Find the "thing" node...
            XPathExpression thingExpr = xpath.compile("/root/thing");
            NodeList things = (NodeList) thingExpr.evaluate(dom, XPathConstants.NODESET);

            System.out.println("Found " + things.getLength() + " thing nodes...");

            // Find the property nodes of thing
            XPathExpression expr = xpath.compile("property");
            NodeList nodes = (NodeList) expr.evaluate(things.item(0), XPathConstants.NODESET);

            System.out.println("Found " + nodes.getLength() + " thing/property nodes...");

            // Find all the property "name" nodes under thing
            expr = xpath.compile("property/name");
            nodes = (NodeList) expr.evaluate(things.item(0), XPathConstants.NODESET);

            System.out.println("Found " + nodes.getLength() + " name nodes...");
            System.out.println("Property value = " + nodes.item(0).getTextContent());

            // Find all nodes that have property nodes
            XPathExpression exprAll = xpath.compile("/root/*/property");
            NodeList nodesAll = (NodeList) exprAll.evaluate(dom, XPathConstants.NODESET);
            System.out.println("Found " + nodesAll.getLength() + " property nodes...");

        } catch (Exception exp) {
            exp.printStackTrace();
        }
    }
}

Which will give you an output of something like

Found 1 thing nodes...
Found 5 thing/property nodes...
Found 5 name nodes...
Property value = Property1
Found 10 property nodes...



回答2:


How about "//thing/name/text()" ?

The double slashes you have now before name mean "anywhere in the tree, not necessarily direct child nodes".




回答3:


Use these XPath expressions:

//thing[name='Thing1']

this selects any thing element in the XML document, that has a name child whose string value is "Thing1".

also use:

//property[name='Property1']

this selects any property element in the XML document, that has a name child whose string value is "Property1".

Update:

To get all text nodes, each containing a string value of a thing element, just do:

//thing/text()

In XPath 2.0 one can get a sequence of the strings themselves, using:

//thing/string(.)

This isn't possible with a single XPath expression, but one can get the string value of a particular (the n-th)thing element like this:

string((//thing)[$n])

where $n must be substituted with a specific number from 1 to count(//thing) .

So, in your prograaming language, you can first determine cnt by evaluating this XPath expression:

count(//thing)

And then in a loop for $n from 1 to cnt dynamically produce the xpath expression and evaluate it:

string((//thing)[$n])

Exactly the same goes for obtaining all the values for property elements.



来源:https://stackoverflow.com/questions/12966127/xpath-and-java-with-repeated-tags

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!