Reputation: 1230
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
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