代码之家  ›  专栏  ›  技术社区  ›  Niko

在根元素语法中使用命名空间前缀解析XML-Java

  •  1
  • Niko  · 技术社区  · 6 年前

    XML 形式:

    <?xml version="1.0" encoding="UTF-8"?>
    <semseg:Envelope xmlns:semseg="http://a-random-URL" xmlns="http://another-random-URL">
        <semseg:subject>Subject</semseg:subject>
        <semseg:Sender>
            <semseg:name>Me</semseg:name>
        </semseg:Sender>
        <Triangle>
            <Triangle time='2017-11-29'>
                <Triangle key='a' value='b'/>
                <Triangle key='c' value='d'/>
                <Triangle key='e' value='f'/>
                <Triangle key='g' value='h'/>
            </Triangle>
        </Triangle>
    </semseg:Envelope>
    

    我正试图找回元素 <Triangle> ( <Triangle time='2017-11-29'> -元素名在这个XML中有点重复) XPath . 部分代码如下:

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setNamespaceAware(true);
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    Document doc = documentBuilder.parse("file.xml");
    
    XPathFactory xPathFactory = XPathFactory.newInstance();
    XPath xPath = xPathFactory.newXPath();
    XPathExpression xpr = xPath.compile("/semseg:Envelope/Triangle");
    NodeList nodes = (NodeList)xpr.evaluate(doc, XPathConstants.NODESET);
    

    XPath语言 XPath语言 具有 this XPath语言 棋盘 XML格式

    /semseg:Envelope/Triangle/Triangle/@time
    

    似乎命名空间前缀有问题。解析 XML格式 不带任何名称空间前缀的 .

    2 回复  |  直到 6 年前
        1
  •  2
  •   GPI    6 年前

    XML输入实际上有两个名称集。

    默认命名空间

    <semseg:Envelope ... xmlns="http://another-random-URL" ...
    

    作为默认名称空间,任何在其上没有名称空间的XML元素都属于此默认名称空间。

    semseg命名空间

    定义如下:

    <semseg:Envelope xmlns:semseg="http://a-random-URL" ...
    

    意思是每个前缀为 semseg

    翻译你的要求

    • 任何 Triangle 任何 三角形 元素来自 http://another-random-URL 命名空间 ).
    • 那是根的直接子代 semseg:Enveloppe 元素(实际上转换为 Enveloppe 属于“ http://a-random-URL “命名空间 ).

    我们创建了一个名称空间上下文,该上下文描述了我们正在使用的名称空间: 我定义要使用的前缀,并将它们映射到命名空间。XPath引擎将使用这些前缀。我的地图:

    • 这个 main http://a-random-URL
    • 这个 secondary 前缀 http://another random URL

    使用我定义的这个映射,我可以将您的需求转换为这个XPath:

    /main:Envelope/secondary:Triangle
    

    XPathFactory xPathFactory = XPathFactory.newInstance();
    XPath xPath = xPathFactory.newXPath();
    xPath.setNamespaceContext(new NamespaceContext() {
        @Override
        public String getNamespaceURI(String prefix) {
            if ("main".equals(prefix)) {
                return "http://a-random-URL";
            }
            if ("secondary".equals(prefix)) {
                return "http://another-random-URL";
            }
            return null;
        }
        @Override
        public String getPrefix(String namespaceURI) {
            // This should be implemented but I'm lazy and this sample works without it
            return null;
        }
    
        @Override
        public Iterator getPrefixes(String namespaceURI) {
            // This should be implemented but I'm lazy and this sample works without it
            return null;
        }
    });
    XPathExpression xpr = xPath.compile("/main:Envelope/secondary:Triangle");
    NodeList nodes = (NodeList)xpr.evaluate(doc, XPathConstants.NODESET);
    System.out.println(nodes.getLength());
    

    输出:

    1
    

    在这里,我实现了一个非常愚蠢的名称空间上下文,但是如果您拥有Spring框架、CXF、guava(我认为)或其他框架,那么您通常会有 SimpleNamespaceContext MapBasedNamespaceContext 这可能是更好的选择。

        2
  •  1
  •   Niko    6 年前

    这对我有用

    /\*[local-name()='Envelope']/\*[local-name()='Triangle']/\*[local-name()='Triangle']/@time