【问题标题】:XMLStreamReader how to work with nested elements of same typeXMLStreamReader 如何处理相同类型的嵌套元素
【发布时间】:2015-08-04 17:13:24
【问题描述】:

我正在使用 XMLStreamReader 并解析以下 XML:

<root>
    <element>
        <attribute>level0</attribute>
        <element>
            <attribute>level1</attribute>
            <element>
                <attribute>level2</attribute>
            </element>
        </element>
    </element>
</root>

我正在构建我的 XMLStreamReader:

XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(
                new ByteArrayInputStream(document.getBytes()));

不幸的是,当我到达带有reader.next(); 的第一个结束元素标记时,我得到了以下异常:

javax.xml.stream.XMLStreamException: ParseError at [row,col]:[7,14]
Message: XML document structures must start and end within the same entity. 

有没有办法覆盖 XMLStreamReader 的默认行为来解决这个问题?

编辑

这是我正在使用的代码:

@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
        throws IOException, InterruptedException {
    String document = value.toString();
    System.out.println("'" + document + "'");
    try {
        XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(
                new ByteArrayInputStream(document.getBytes()));
        String propertyName = "";
        String propertyValue = "";
        String currentElement = "";
        while (reader.hasNext()) {
            int code = reader.next();
            switch (code) {
            case START_ELEMENT:
                currentElement = reader.getLocalName();
                break;
            case CHARACTERS:
                if (currentElement.equalsIgnoreCase("element")) {
                    propertyName += reader.getText();
                } else if (currentElement.equalsIgnoreCase("attribute")) {
                    propertyValue += reader.getText();
                }
                break;
            }
        }
        reader.close();
        context.write(new Text(propertyName.trim()), new Text(propertyValue.trim()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【问题讨论】:

  • 您的 XML 可能格式不正确,我猜真正的 XML 文档不是您在帖子中放的,因为看起来还可以。
  • @biziclop 我已经用那个确切的 XML 进行了测试。它给出的错误是有效的......读者抛出它是因为它到达了第三个元素的结束标签并认为我正在尝试关闭第一个元素。我想知道的是,有没有办法解决这个问题?
  • 它绝对不会那样做。您的 XML 或您的代码(您的问题中没有包含)有问题。
  • @biziclop 查看代码编辑。感谢您的意见。

标签: java xml xmlstreamreader


【解决方案1】:

示例 XML 文档和/或 StAX 解析器没有任何问题,可以使用以下代码进行检查:

@Test
public void testSO_31815379() throws XMLStreamException, UnsupportedEncodingException {
    final String xml = 
        "<root>\n" +
        "    <element>\n" +
        "        <attribute>level0</attribute>\n" +
        "        <element>\n" +
        "            <attribute>level1</attribute>\n" +
        "            <element>\n" +
        "                <attribute>level2</attribute>\n" +
        "            </element>\n" +
        "        </element>\n" +
        "    </element>\n" +
        "</root>";

    final XMLStreamReader reader = XMLInputFactory.newInstance()
        .createXMLStreamReader(new ByteArrayInputStream(xml.getBytes("UTF-8")));
    LOG.info("Using XMLStreamReader implementation: %s", reader.getClass().getName());

    reader.require(XMLStreamConstants.START_DOCUMENT, null, null);
    int event;
    while ((event = reader.next()) != XMLStreamConstants.END_DOCUMENT) {
        LOG.info(StaxUtils.eventDescription(reader));
    }
    reader.require(XMLStreamConstants.END_DOCUMENT, null, null);
    reader.close();
}

输出(StaxUtils.eventDescription 是自定义辅助方法)

Using XMLStreamReader implementation: com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl
START_ELEMENT<{}root>
CHARACTERS=<whitespace>
START_ELEMENT<{}element>
CHARACTERS=<whitespace>
START_ELEMENT<{}attribute>
CHARACTERS='level0'
END_ELEMENT<attribute>
CHARACTERS=<whitespace>
START_ELEMENT<{}element>
CHARACTERS=<whitespace>
START_ELEMENT<{}attribute>
CHARACTERS='level1'
END_ELEMENT<attribute>
CHARACTERS=<whitespace>
START_ELEMENT<{}element>
CHARACTERS=<whitespace>
START_ELEMENT<{}attribute>
CHARACTERS='level2'
END_ELEMENT<attribute>
CHARACTERS=<whitespace>
END_ELEMENT<element>
CHARACTERS=<whitespace>
END_ELEMENT<element>
CHARACTERS=<whitespace>
END_ELEMENT<element>
CHARACTERS=<whitespace>
END_ELEMENT<root>

【讨论】:

  • 谢谢,但这不起作用。如果我尝试获取元素的文本,则会收到以下错误:Message: elementGetText() function expects text only elment but START_ELEMENT was encountered.
  • 代码的工作方式与演示一样 :) 如果您需要来自元素的文本,则必须在光标位于 CHARACTERS 事件时调用 reader#getText()(或相关函数)(参见示例输出,显示所有数据!)。如果您发布麻烦的代码,我们可以更好地帮助您。
  • 让您的代码工作。贴出我麻烦的代码。感谢您的意见。
  • 额外提示:1) 总是在您的switch 语句中使用default 子句。如果使用XMLStreamReader,您应该使用堆栈或双端队列来跟踪访问的元素。
  • 原来是格式错误的 xml...在 XML 中发送的函数正在剥离最终的元素标记。感谢您的帮助。
猜你喜欢
  • 2021-11-27
  • 2021-06-11
  • 2014-05-08
  • 1970-01-01
  • 2015-02-14
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多