Diego Macario
Diego Macario

Reputation: 1230

How to get a value from a element?

I´m trying to get one value from a String, this source cames from a xml.

<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">

So I want to get the value from versao atributte.

My code is

try {
    XPathFactory xPathFactory = XPathFactory.newInstance();
    XPath xPath = xPathFactory.newXPath();

    InputSource inputSource = new InputSource(new StringReader(source));
    String versao = xPath.evaluate("//nfeProc[@versao]", inputSource);

    versao.toString();
} catch (XPathExpressionException e) {
    e.printStackTrace();
}  

Always returning null

I´m using Java.

Upvotes: 0

Views: 177

Answers (1)

Luke Woodward
Luke Woodward

Reputation: 64949

Your problem is with XPath and namespaces.

Your nfeProc element is in the namespace with the URI http://www.portalfiscal.inf.br/nfe. However, you do not bind any prefixes to namespaces in your xPath, so it searches for an element named nfeProc in the default namespace. No such element exists, so you get nothing back.

What you need to do is to bind a prefix to the namespace in your XPath object as well as in your XML. In Java, this is done by using a NamespaceContext object. Awkwardly, however, NamespaceContext is an interface, and it isn't always easy getting hold of an implementation of it.

Note additionally that in XPath an unprefixed name, such as nfeProc in your example, is always in the default namespace (i.e. that with an empty namespace URI). You cannot rebind the default namespace prefix to some other URI, so you will need to choose another prefix instead, for example, nfe, and then use this prefix in your XPath. There isn't a problem with this: if abc and xyz are both bound to the same namespace URI, then abc:someElement and xyz:someElement are the same name.

@MostyMostacho correctly points out that your XPath expression isn't quite right. Evaluating //nfe:nfeProc[@versao] would return the text content of nfe:nfeProc elements that have a versao attribute, but you want the value of this attribute. So, the XPath expression you want is //nfe:nfeProc/@versao. (Note that attributes don't inherit namespaces from parent elements, so the name of your versao attribute is still in the default namespace.)

Putting it all together, using a custom NamespaceContext implementation, we arrive at the following:

import java.io.StringReader;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.xml.sax.InputSource;

public class XPathTest {
    public static void main(String[] args) throws Exception {
        String source = "<nfeProc xmlns=\"http://www.portalfiscal.inf.br/nfe\" versao=\"2.00\"></nfeProc>";

        try {
            XPathFactory xPathFactory = XPathFactory.newInstance();
            XPath xPath = xPathFactory.newXPath();

            NamespaceContext context = new NamespaceContext() {
                private static final String PREFIX = "nfe";
                private static final String URI = "http://www.portalfiscal.inf.br/nfe";

                @Override
                public String getNamespaceURI(String prefix) {
                    return (PREFIX.equals(prefix)) ? URI : XMLConstants.NULL_NS_URI;
                }

                @Override
                public String getPrefix(String namespaceUri) {
                    return (URI.equals(namespaceUri)) ? PREFIX : XMLConstants.DEFAULT_NS_PREFIX;
                }

                @Override
                public Iterator getPrefixes(String namespaceUri) {
                    return Collections.singletonList(this.getPrefix(namespaceUri)).iterator();
                }
            };

            xPath.setNamespaceContext(context);

            InputSource inputSource = new InputSource(new StringReader(source));
            String versao = xPath.evaluate("//nfe:nfeProc/@versao", inputSource);

            System.out.println(versao.toString());
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        }
    }
}

When I run this, I get the following output:

C:\Users\Luke\Java>java XPathTest
2.00

Upvotes: 3

Related Questions