gpt4 book ai didi

java - 使用 StAX 解混——如果元素之间没有空格,它会跳过这些元素

转载 作者:行者123 更新时间:2023-11-30 08:50:20 25 4
gpt4 key购买 nike

上下文

我需要解析 XML。这个 XML 很大,所以我使用 StAx 来处理我感兴趣的每个元素。我使用 JDK 附带的默认实现。

问题

当一个 XML 元素在另一个相同类型的元素之前(例如 <person> )并且它们之间没有任何字符时,它会跳过第二个。所以如果我有 10 个接一个,我只能解码 5 个人。例如:

<people><person>..</person><person>..</person></people>

我构建了一个测试来针对封装在方法 countUnmarshalledPersonEntities() 中的一段代码显示此行为.

问题是,当元素之间有空格时,例如:

<people><person><id>1</id></person> <person><id>2</id></person></people>

它解码两个实体,没关系。

但是当节点之间没有空格时,例如:

<people><person><id>1</id></person><person><id>2</id></person></people>

第一次解码跳过下一个开放标签 <person> , 然后忽略第二个人。我只解析 1 个实体。

测试

package org.opensource.lab.stream;

import static org.junit.Assert.assertEquals;

import java.io.InputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class StreamParserProblemTest {
private XMLInputFactory xmlif;
private XMLStreamReader xmlStreamReader;
private Unmarshaller personUnmarshaller;

private final InputStream xmlStreamPersonsNoSeparated = IOUtils.toInputStream(
"<people><person><id>1</id></person><person><id>2</id></person></people>"
);
private final InputStream xmlStreamWithPersonsWhitespaceSeparated = IOUtils.toInputStream(
"<people><person><id>1</id></person> <person><id>2</id></person></people>"
);

@Before
public void setUp() throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
personUnmarshaller = jaxbContext.createUnmarshaller();
xmlif = XMLInputFactory.newInstance();
}

@After
public void cleanUp() throws Exception {
if(xmlStreamReader != null) {
xmlStreamReader.close();
}
}

@XmlRootElement(name = "person")
static class Person {
String id;
}

@Test
public void whenNoSpacesBetweenNodes_shouldFind2Persons_FAIL() throws Exception {
xmlStreamReader = xmlif.createXMLStreamReader(xmlStreamPersonsNoSeparated, "UTF-8");

int personTagsFound = countUnmarshalledPersonEntities();

assertEquals(personTagsFound, 2);
}

/**
* I don't know why, but if there's at least one whitespace character between node of the same type it won't skip.
*
* @throws Exception in a test
*/
@Test
public void whenWithSpacesBetweenNodes_shouldFind2Persons_SUCCESS() throws Exception {
xmlStreamReader = xmlif.createXMLStreamReader(xmlStreamWithPersonsWhitespaceSeparated, "UTF-8");

int personTagsFound = countUnmarshalledPersonEntities();

assertEquals(personTagsFound, 2);
}

/**
* CODE to test.
*
* @return number of unmarshalled persons (people).
* @throws Exception
*/
private int countUnmarshalledPersonEntities() throws Exception {
int personTagsFound = 0;

while (xmlStreamReader.hasNext()) {
int type = xmlStreamReader.next();

if (type == XMLStreamConstants.START_ELEMENT && xmlStreamReader.getName().toString().equalsIgnoreCase("person")) {
personUnmarshaller.unmarshal(xmlStreamReader, Person.class);
personTagsFound++;
}
}

return personTagsFound;
}
}

代码有什么问题吗?

谢谢。

最佳答案

感谢您附加的单元测试,这确实让理解变得更容易了!

当您对 xmlStreamReader 执行unmarshal 时,只要有属于您的标签,XMLStreamReader 就会自行隐式调用 next实体。因此,在结束 person 标记之后,它将调用 next 并指向下一个实体的第一个 person 标记。在下一次迭代中调用 xmlStreamReader.next() 时,您将跳过它。如果您的实体之间有空格,则不会发生这种情况,因为在解析之后,您的阅读器会指向空格。

这个修改后的代码对我有用,你的两个单元测试都成功了:

    while (xmlStreamReader.hasNext()) {
if (xmlStreamReader.isStartElement() && xmlStreamReader.getName().toString().equalsIgnoreCase("person")) {
personUnmarshaller.unmarshal(xmlStreamReader, Person.class);
personTagsFound++;
} else {
xmlStreamReader.next();
}
}

关于java - 使用 StAX 解混——如果元素之间没有空格,它会跳过这些元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31013366/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com