0

我试图从一个字符串中获取一个值,这个来源来自一个 xml。

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

所以我想从属性中获取价值versao

我的代码是

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();
}  

总是返回 null

我正在使用Java。

4

1 回答 1

3

您的问题在于 XPath 和命名空间。

您的nfeProc元素位于具有 URI 的命名空间中http://www.portalfiscal.inf.br/nfe。但是,您没有将任何前缀绑定到 中的命名空间xPath,因此它会搜索nfeProc在默认命名空间中命名的元素。不存在这样的元素,所以你什么也得不到。

您需要做的是将前缀绑定到 XPath 对象以及 XML 中的命名空间。在 Java 中,这是通过使用NamespaceContext对象来完成的。然而,尴尬的是,NamespaceContext 是一个接口,要获得它的实现并不总是那么容易

另外请注意,在 XPath 中,无前缀名称(例如nfeProc在您的示例中)始终位于默认名称空间中(即具有空名称空间 URI 的名称)。您不能将默认名称空间前缀重新绑定到其他 URI,因此您需要选择另一个前缀,例如 ,nfe然后在您的 XPath 中使用此前缀。这没有问题:如果abcxyz都绑定到同一个命名空间 URI,那么abc:someElementxyz:someElement是同一个名称。

@MostyMostacho 正确指出您的 XPath 表达式不太正确。评估//nfe:nfeProc[@versao]将返回nfe:nfeProc具有versao属性的元素的文本内容,但您需要此属性的值。因此,您想要的 XPath 表达式是//nfe:nfeProc/@versao. (请注意,属性不会从父元素继承命名空间,因此您的versao属性名称仍在默认命名空间中。)

综上所述,使用自定义 NamespaceContext 实现,我们得到以下结果:

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();
        }
    }
}

当我运行它时,我得到以下输出:

C:\Users\Luke\Java>java XPathTest
2.00
于 2013-11-09T20:09:39.063 回答