Marcus Junius Brutus
Marcus Junius Brutus

Reputation: 27286

XPath predicates in conditional expressions

I have the following XML instance:

<entities>
    <person>
        James
    </person>
    <legalEntity legalName="ACME">
    </legalEntity>
    <criminalOrganization>
        <organizationName>Mafia</organizationName>
    </criminalOrganization>
</entities>

And wish to produce a print-out with the type and name of each entity.

type is simply the element name (person, legalEntity or criminalOrganization), name is defined differently according to the kind of entity.

So I have the following code:

XPathExpression expr = xpath.compile("/entities/(person|legalEntity|criminalOrganization)");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
    Node node = nodes.item(i);
    String nodeName = node.getNodeName();
    XPathExpression exprInner = xpath.compile("text()|@legalName|organizationName/text()");
    String name = (String) exprInner.evaluate(node);
    System.out.printf("node type = %s, name = %s\n", nodeName, name);
}

The code produces the output:

 node type = person, name = 
         James

 node type = legalEntity, name = ACME
 node type = criminalOrganization, name =

So basically, the name of person entities is fetched OK (I just have to trim it), the name of legalEntity is also fetched properly, but the name of criminalOrganization is not.

Upon investigation I discovered that this is due to the fact that the first expression in the XPath union structure: text()|@legalName|organizationName/text() also evaluates (I suppose to some empty string value) in the case of criminalOrganization so it is returned as the evaluated value of the entire union expression (rather than the last component organizationName/text()).

My questions are:

  1. why does this mixup not happen also in the case of legalEntity?

  2. how do I include element name predicates in the union XPath expression to ensure that each component evaluates only for the intended type. I.e. text() for person elements, @legalName for legalEntity elements and organizationName/text() for criminalOrganization elements ?

Upvotes: 0

Views: 648

Answers (1)

hr_117
hr_117

Reputation: 9627

In my opinion your solution is somehow a little bit strange but you may try to use self:: .

Try this (not tested):

XPathExpression exprInner 
      = xpath.compile("self::person/text()|
                       self::legalEntity/@legalName|
                       self::criminalOrganization/organizationName/text()");

Upvotes: 1

Related Questions