首页 文章

从Stax XMLStreamReader读取以解组部分

提问于
浏览
2

我正在使用Stax游标api从大型xml文件中提取数据 . 当前我转到特殊标记的开头并使用JAXB解组标记 . 这适用于格式良好的xml文件 . 但不久前,我有一份文件,其中数十万个标签中的一个没有关闭 . JAXB使用XMLStreamReader,直到文档结束并失败 . 有没有办法从开始标记读取到结束标记并解组这个单独的标记?所以我会丢失两个带有Exception的标签而不是文档的其余部分 . 我找到的唯一方法是使用普通的BufferedReader而不是XMLStreamReader并检查行内容 . 但这个解决方案在我看来很难看 .

1 回答

  • 0

    我使用jackson对XML片段进行反序列化取得了一定的成功 . 当单个读取失败时,可以通过将光标前进到下一个片段来恢复该过程:

    import com.fasterxml.jackson.dataformat.xml.XmlMapper;
    
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.stream.XMLInputFactory;
    import javax.xml.stream.XMLStreamConstants;
    import javax.xml.stream.XMLStreamException;
    import javax.xml.stream.XMLStreamReader;
    import java.io.StringReader;
    
    public class XmlFragmentReader {
        public static void main(String[] args) throws XMLStreamException {
            String xml =
                "<list>\n" +
                "<object><name>a</name></object>\n" +
                "<object><name>b</name>\n" + // Missing closing tag
                "<object><name>c</name></object>\n" +
                "<object><name>d</name></object>\n" +
                "<object><name>e</name></object>\n" +
                "</list>";
    
            XMLStreamReader reader = XMLInputFactory
                .newInstance()
                .createXMLStreamReader(new StringReader(xml));
    
            XmlMapper mapper = new XmlMapper();
            while (next(reader, "object")) {
                try {
                    Obj obj = mapper.readValue(reader, Obj.class);
                    System.out.println("Read: " + obj.getName());
                } catch (Exception e) {
                    System.err.println("Read Failed: " + e);
                }
            }
        }
    
        // Advance cursor to the opening tag <name>
        private static boolean next(XMLStreamReader reader, String name) throws XMLStreamException {
            while (true) {
                if (reader.getEventType() == XMLStreamConstants.START_ELEMENT && reader.getLocalName().equals(name)) {
                    return true;
                } else if (!reader.hasNext()) {
                    return false;
                }
                reader.next();
            }
        }
    
        // Test object
        @XmlRootElement(name = "object")
        public static class Obj {
            private String name;
    
            @XmlElement
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    }
    

    输出:

    Read a
    Read d
    Read e
    

相关问题