【问题标题】:How to parse an XML partially (only 1 level deep)如何部分解析 XML(只有 1 级深度)
【发布时间】:2014-03-13 03:12:41
【问题描述】:

输入 (fullInput)

想象一下,我将以下内容作为InputStream(或作为从该流读取的内存中的String):

<?xml version="1.0" ?>
<root>
    <element attr="val1"><x /><y /></element>
    <element attr="val2"><y /></element>
    <element attr="val3"><x /><x /></element>
    <element attr="val4"><z /><y /></element>
</root>

我想如何使用解决方案 (bridgeXml)

IProprietaryUnmarshaller UNMARSHALLER = ...;
List<Element> parseFullXml(String fullInput) throws UnmarshallException {
    List<String> inputs = bridgeXml(fullInput);
    List<Element> outputs = new ArrayList();
    for(String input : inputs) {
         Element e = UNMARSHALLER.unmarshall(input);
         outputs.add(e);
    }
    return outputs;
}

我在寻找什么

我正在寻找bridgeXml 的/idea 的实现,其中输入String/*Stream 被分成更小的字符串,这些字符串本身是格式良好的XML 文档(没有XML 声明)。

我想避免的琐碎实现

下面的实现容易出错,不灵活,不应该使用,我正在寻找一个使用某种库或 XML 解析器的合适的实现!

List<String> bridgeXml(String input) {
    // strip anything up to the opening root element, and LTrim the remainder
    input = input.replaceAll("(?s)^.*<root.*?>\\s*", "");
    // strip anything after the closing root element, and RTrim the remainder
    input = input.replaceAll("(?s)\\s*</root.*$", "");
    // split at </element> closing tags, not removing them (?<= does the magic)
    return Arrays.asList(input.split("(?<=</element>)"));
}

限制

  • XML 输入无法更改,它是完全有效的 XML。
  • 必须使用专有的解组器,并且不能修改。
  • 我正在寻找一种解决方案,其中文件不是 XML 解组、XML 编组、专有解组。
  • (不要挑剔 XML/Java 代码样式、格式、可见性修饰符等!
    这些是简化的代码,便于沟通。)

解决方案(编辑)

我最终写了这篇文章...我最终对 XML 进行了双重解析(请参阅getOuterXml),因为现在假设它很慢还为时过早。我有一个巨大的数据库查询,这很慢。

protected <T> List<T> read(InputStream inputStream, String tagName) throws XMLStreamException,
    TransformerException, DecodingException
{
    List<T> result = new ArrayList<T>();
    XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
    XMLStreamReader xmlReader = xmlFactory.createXMLStreamReader(inputStream, "ISO-8859-1");
    while (xmlReader.hasNext()) {
        xmlReader.next();
        if (xmlReader.isStartElement() && tagName.equals(xmlReader.getLocalName())) {
            String output = getOuterXml(xmlReader);
            @SuppressWarnings("unchecked")
            T object = (T) UNMARSHALLER.unmarshall(output);
            result.add(object);
        }
    }
    return result;
}

protected String getOuterXml(XMLStreamReader xmlr) throws TransformerException
{
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    StringWriter stringWriter = new StringWriter();
    transformer.transform(new StAXSource(xmlr), new StreamResult(stringWriter));
    return stringWriter.toString();
}

protected <T> List<T> getObjects(String urlString, String tagName)
{
    LOG.info("Downloading [{}] updates from [{}].", tagName, urlString);
    HttpURLConnection conn = null;
    InputStream inputStream = null;
    try {
        URL url = new URL(urlString);
        conn = (HttpURLConnection) url.openConnection();
        conn.connect();
        inputStream = conn.getInputStream();
        return read(inputStream, tagName);
    } catch (Exception ex) {
        String exceptionMessage = "Updating [" + tagName + "] from [" + urlString + "] failed.";
        LOG.error(exceptionMessage, ex);
        throw new MyFancyWrapperException(exceptionMessage, ex);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException ex) {
                LOG.warn("Cannot close HTTP's input stream", ex);
            }
        }
        if (conn != null) {
            conn.disconnect();
        }
    }
}

【问题讨论】:

  • 您已经用 stax 标记了您的问题。这就是我建议你的。有了它,您可以流式传输 xml 文档或其中的一部分,并使用 JAXB 解析有效的子 xml。这就是我已经为 unmarshaller 拆分非常大的 xml 文档和一些有趣的部分所做的工作。

标签: java xml jaxb unmarshalling stax


【解决方案1】:

所以这里是一个用于示例 xml 的小 stax 解析器:

String xml = "<root><element>test</element></root>";
XMLInputFactory xmlif = XMLInputFactory.newInstance();
XMLStreamReader xmlr = xmlif.createXMLStreamReader(new StringReader(xml));
while (xmlr.hasNext()) {
    xmlr.next();
    if (xmlr.isStartElement() || xmlr.isEndElement()) {
        System.out.println(xmlr.getLocalName() + " " + xmlr.getEventType());
    }
}

在这里您会找到解释,说明如何将 stax 与 jaxb 结合使用。

http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html

【讨论】:

  • 谢谢,听起来不错,我明天试试!
猜你喜欢
  • 2011-09-09
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 2011-08-18
相关资源
最近更新 更多