【问题标题】:Parse XML file to get all Namespace information解析 XML 文件以获取所有命名空间信息
【发布时间】:2012-07-11 16:54:47
【问题描述】:

我希望能够从给定的 XML 文件中获取所有命名空间信息。

例如,如果输入的 XML 文件是这样的:

<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
   <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
      <ns1:id>1</ns1:id>
      <description>bar</description>
      <name>foo</name>
      <ns1:price>
         <amount>00.00</amount>
         <currency>USD</currency>
      </ns1:price>
      <ns1:price>
         <amount>11.11</amount>
         <currency>AUD</currency>
      </ns1:price>
   </ns1:article>
   <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
      <ns1:id>2</ns1:id>
      <description>some name</description>
      <name>some description</name>
      <ns1:price>
         <amount>00.01</amount>
         <currency>USD</currency>
      </ns1:price>
   </ns1:article>
</ns1:create>

我希望输出看起来像这样(在这种情况下以逗号分隔):

create, ns1, http://predic8.com/wsdl/material/ArticleService/1/
article, ns1, http://predic8.com/material/1/
price, ns1, http://predic8.com/material/1/
id, ns1, http://predic8.com/material/1/

重要提示:

重要的是,我们还要考虑在特定命名空间内定义的子节点,但其定义可能在更高的节点上定义。比如我们还是要挑节点ns1:id,这里需要回溯到父节点ns1:article发现namespace url是xmlns:ns1='http://predic8.com/material/1/

我正在使用 Java 实现,所以我不介意基于 Java 的解决方案,甚至基于 XSLT 的解决方案似乎都合适。

【问题讨论】:

  • 那么您到底在寻找什么样的信息?输出中的第一行有一个本地名称、一个命名空间前缀和一个命名空间名称,但接下来的三行以看起来像命名空间声明属性的东西结尾,但奇怪的是缺少结束 ' 分隔符。那么属性节点的限定名呢,你也对它们感兴趣吗?
  • 谢谢,我现在已经编辑了问题,因为这是一个错误。我真的很喜欢(本地名称,前缀,url)形式的三元组。另外,现在我不想担心合格的属性节点。
  • Larry,最好指出一个事实,即当前接受的答案既不处理默认命名空间中的名称,也不处理命名空间属性名称。此外,它过于复杂且难以阅读。将此与 XSLT 2.0 解决方案进行比较,该解决方案实际上是对单个 XPath 表达式的评估——正如其他两个答案中提供的那样......
  • Dimitre,我当然同意,虽然我知道问题中没有明确规定,但这似乎是完整解决方案的关键要求。毕竟,我确实提到了“所有”命名空间信息。感谢您指出这一点并提供解决此问题的解决方案 (+1)。我也相应地修改了正确答案以反映更正确的解决方案。
  • Larry,虽然您的问题可能很有趣且具有挑战性,但我们确实希望您尝试自己解决这些问题(并发布您的代码,即使它不起作用),而不是要求社区为您提供完整的解决方案。谢谢。

标签: java xml xslt xpath xquery


【解决方案1】:

这可以通过一个 XPath 2.0 表达式来完成:

distinct-values(//*[name()!=local-name()]/
   concat(local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri())

【讨论】:

  • 这似乎没有涵盖默认命名空间中的元素名称——还是我错了?
  • 通过更改谓词可以轻松适应处理默认命名空间或无命名空间中的元素名称,但问题并没有明确要求是什么,所以我猜测。跨度>
【解决方案2】:

我会使用内置的XMLStreamReader,它是流式XML 解析器实现的接口(从XMLInputFactory 类中获取)。它的getName 方法返回一个 QName,它应该可以为您提供所需的一切。

类似的东西:

File file = new File("samples/sample11.xml");
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory.createXMLStreamReader(new FileInputStream(file));
Set<String> namespaces = new HashSet<String>();
while (reader.hasNext()) {
      int evt = reader.next();
      if (evt == XMLStreamConstants.START_ELEMENT) {
        QName qName = reader.getName();
        if(qName != null){
            if(qName.getPrefix() != null && qName.getPrefix().compareTo("")!=0)
                namespaces.add(String.format("%s, %s, %s",
                    qName.getLocalPart(), qName.getPrefix(), qName.getNamespaceURI()));
        }
      }
}

for(String namespace : namespaces){
    System.out.println(namespace);              
}

【讨论】:

  • 谢谢亚历克斯,这很好用。我已编辑您的解决方案以提供更完整的解决方案(目前仍在等待同行评审)。
【解决方案3】:

进一步开发了 Michael Kay 提出的 XPath 表达式(实际上似乎是一种简化),也可以处理属于默认命名空间的无前缀元素名称:

distinct-values(//*[namespace-uri()]
                    /concat(local-name(),
                            ', ',
                            substring-before(name(), ':'),
                            ', ',
                            namespace-uri(),
                            '&#xA;'
                            )
                )

当在以下文档上评估此 XPath 表达式时(提供的文档,但添加了一个位于默认命名空间中的元素):

<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
    <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
        <ns1:id>1</ns1:id>
        <description>bar</description>
        <name>foo</name>
        <ns1:price>
            <amount>00.00</amount>
            <currency>USD</currency>
        </ns1:price>
        <ns1:price>
            <amount>11.11</amount>
            <currency>AUD</currency>
        </ns1:price>
    </ns1:article>
    <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
        <ns1:id>2</ns1:id>
        <description>some name</description>
        <name>some description</name>
        <ns1:price>
            <amount>00.01</amount>
            <currency>USD</currency>
        </ns1:price>
        <quality xmlns="my:q">high</quality>
    </ns1:article>
</ns1:create>

产生想要的正确结果

 create, ns1, http://predic8.com/wsdl/material/ArticleService/1/
 article, ns1, xmlns:ns1='http://predic8.com/material/1/
 id, ns1, xmlns:ns1='http://predic8.com/material/1/
 price, ns1, xmlns:ns1='http://predic8.com/material/1/
 quality, , my:q

还有一点改进是为属性名称生成命名空间数据:

distinct-values(//(*|@*)[namespace-uri()]
                    /concat(if(. intersect ../@*)
                              then '@'
                              else (),
                            local-name(),
                            ', ',
                            substring-before(name(), ':'),
                            ', ',
                            namespace-uri(),
                            '&#xA;'
                            )
                )

当在以下 XML 文档上评估此 XPath 表达式时(前一个(上)在article 元素之一上添加了xml:lang 属性):

<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
    <ns1:article xml:lang="en-us" xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
        <ns1:id>1</ns1:id>
        <description>bar</description>
        <name>foo</name>
        <ns1:price>
            <amount>00.00</amount>
            <currency>USD</currency>
        </ns1:price>
        <ns1:price>
            <amount>11.11</amount>
            <currency>AUD</currency>
        </ns1:price>
    </ns1:article>
    <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
        <ns1:id>2</ns1:id>
        <description>some name</description>
        <name>some description</name>
        <ns1:price>
            <amount>00.01</amount>
            <currency>USD</currency>
        </ns1:price>
        <quality xmlns="my:q">high</quality>
    </ns1:article>
</ns1:create>

再次产生正确的结果:

 create, ns1, http://predic8.com/wsdl/material/ArticleService/1/
 article, ns1, xmlns:ns1='http://predic8.com/material/1/
 @lang, xml, http://www.w3.org/XML/1998/namespace
 id, ns1, xmlns:ns1='http://predic8.com/material/1/
 price, ns1, xmlns:ns1='http://predic8.com/material/1/
 quality, , my:q

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-08
    • 2020-01-02
    • 2018-12-07
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    相关资源
    最近更新 更多