【问题标题】:How to read namespace as it is in a xml using XMLStreamReader?如何使用 XMLStreamReader 读取 xml 中的命名空间?
【发布时间】:2014-08-05 09:24:50
【问题描述】:

我有一个使用 XMLStreamReader 对象从中读取的 xml 文件。 所以我会保持简单:

让我们以这个 xml 示例为例:

<mySample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attribute1="value1"/>

所以我需要的是获取值(作为字符串)“xmlns:xsi”并获取值(也作为字符串)“http://www.w3.org/2001/XMLSchema-instance

我确实尝试过这样的测试:

if (reader.getEventType() != XMLStreamConstants.NAMESPACE){
       attributeName = reader.getAttributeLocalName(i);
       attributeValue = reader.getAttributeValue(i);
}
else{
       attributeName = reader.getNamespacePrefix(i) + reader.getNamespaceURI(i);
       attributeValue = reader.getAttributeValue(i);
}

但它不起作用。

显然我错过了作为这个 API 的新手的一些东西,所以非常欢迎任何帮助。

【问题讨论】:

    标签: java xml stax xmlstreamreader


    【解决方案1】:

    JSR-173 规范(Java 的 Stax API)声明了以下关于 NAMESPACE 事件:

    命名空间
    命名空间声明也可以存在于 StartElement 之外,并且可以报告为 独立信息项。 一般来说,命名空间是作为 StartElement 的一部分报告的 事件。当命名空间是 XQuery 或 XPath 表达式的结果时,它们可能是 报告为独立事件。

    因此,如果您正在查看命名空间事件,您很可能应该检查 StartElement 事件并检查它们。再次,从规范:

    可以使用以下方法访问命名空间:

    int getNamespaceCount();
    String getNamespacePrefix(int index);
    String getNamespaceURI(int index);

    只有在当前 StartElement 上声明的命名空间可用。清单确实 不包含先前声明的命名空间,也不会删除重新声明的命名空间。

    在解析过程中的任何时候,您都可以获得当前完整的命名空间上下文:

    当前状态的命名空间上下文可通过调用获得 XMLStreamReader.getNamespaceContext()StartElement.getNamespaceContext()。这些方法返回一个实例 javax.xml.namespace.NamespaceContext接口。

    这是理论上的:大多数命名空间声明来自 START_ELEMENT,有些可能是独立的。

    在实践中,我从未遇到过 API 在读取文件时报告的 NAMESPACE 事件。它几乎总是报告为 START_ELEMENT 的一部分(并在相应的 END_ELEMENT 中重复),因此如果您对命名空间声明感兴趣,则必须检查 START_ELEMENT。例如,从您的文档开始:

    String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><mySample xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" attribute1=\"value1\"/>";
    XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml));
    while (reader.hasNext()) {
      int event = reader.next();
      if (XMLStreamConstants.START_ELEMENT == event) {
        if (reader.getNamespaceCount() > 0) {
          // This happens
          System.out.println("ELEMENT START: " + reader.getLocalName() + " , namespace count is: " + reader.getNamespaceCount());
          for (int nsIndex = 0; nsIndex < reader.getNamespaceCount(); nsIndex++) {
            String nsPrefix = reader.getNamespacePrefix(nsIndex);
            String nsId = reader.getNamespaceURI(nsIndex);
            System.out.println("\tNamepsace prefix: " + nsPrefix + " associated with URI " + nsId);
          }
        }
      } else if(XMLStreamConstants.NAMESPACE == event) {
        // This almost never happens
        System.out.println("NAMESPACE EVENT");
      }
    }
    

    将产生:

    元素开始:mySample,命名空间计数为:1

    Namepsace 前缀:与 URI http://www.w3.org/2001/XMLSchema-instance 关联的 xsi

    底线:您应该检查 NAMESPACE 和 START_ELEMENT 事件,即使大多数时候,您只会有 START_ELEMENT 报告命名空间声明,它不是一个或另一个,而是两者。

    【讨论】:

    • 感谢 GPI 的回答!理论上我得到了原则,但似乎还有另一个问题。阅读器(从 xml 文件上的 inputStream 创建的 XMLStreamReader)不考虑“xmlns:xsi”(reader.getEventType() 似乎永远不会返回 NAMESPACE)所以当我尝试首先读取并且唯一的值是“attribute1”和“value1”我应该在阅读器上迭代以搜索 eventtype NAMESPACE 吗?
    • 顺便说一句,我不明白这部分“我想如果您通过 StaxAPI 构建 XML 处理管道,可能会发生这种情况,也许正如建议的那样,中间有一个 XSLT 处理引擎,这可能在过程中的不同点发出 NAMESPACE 类型的 XML 事件。"对不起,我缺乏知识,但你能解释一下吗? :)
    • 谢谢,我会试一试 :) 我会及时通知你结果
    • 问题解决了,非常感谢 GPI :) 顺便问一下,你能确认一下 xmlns 声明总是设置在节点的开头吗?
    • 我可以确认 NS 声明总是出现在 XML 元素的开头,这是规范的。但是 XMLStreamReader 可以通过 START_ELEMENT 声明免费向您报告(尽管如前所述,我从未见过)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    相关资源
    最近更新 更多