【问题标题】:How would you use Java to handle various XML documents?您将如何使用 Java 来处理各种 XML 文档?
【发布时间】:2008-08-27 16:55:59
【问题描述】:

我正在寻找使用 Java 应用程序解析各种 XML 文档的最佳方法。我目前正在使用 SAX 和自定义内容处理程序执行此操作,并且效果很好 - 快速且稳定。

我决定探索具有相同程序的选项,该程序当前接收单一格式的 XML 文档,接收两种额外的 XML 文档格式,以及各种 XML 元素更改。我希望根据文档中的第一个“startElement”将 ContentHandler 换成适当的...但是,呃,呃,设置了 ContentHandler 并且 然后 解析了文档!

... constructor ...
{
SAXParserFactory spf = SAXParserFactory.newInstance();

try {
SAXParser sp = spf.newSAXParser();
parser = sp.getXMLReader();
parser.setErrorHandler(new MyErrorHandler());
} catch (Exception e) {} 

... parse StringBuffer ...
try {
parser.setContentHandler(pP);
parser.parse(new InputSource(new StringReader(xml.toString())));
return true;
} catch (IOException e) {
    e.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}
...

所以,我似乎无法按照我最初认为的方式做到这一点。

话虽如此,我认为这完全错误吗?用相同的 XML 处理代码解析多个离散的 XML 文档的最佳方法是什么? I tried to ask in a more general post earlier... but, I think I was being too vague。出于速度和效率的目的,我从未真正关注过 DOM,因为这些 XML 文档相当大,系统每隔几分钟就会收到大约 1200 个。这只是一种信息发送方式

这个问题太长了,增加了我的困惑;以下是一些我想要一个 SAX、StAX 或 ?? 的各种 XML 文档的模型。解析器干净地处理。

products.xml:

<products>
<product>
  <id>1</id>
  <name>Foo</name>
<product>
  <id>2</id>
  <name>bar</name>
</product>
</products>

stores.xml:

<stores>
<store>
  <id>1</id>
  <name>S1A</name>
  <location>CA</location>
</store>
<store>
  <id>2</id>
  <name>A1S</name>
  <location>NY</location>
</store>
</stores>

managers.xml:

<managers>
<manager>
  <id>1</id>
  <name>Fen</name>
  <store>1</store>
</manager>
<manager>
  <id>2</id>
  <name>Diz</name>
  <store>2</store>
</manager>
</managers>

【问题讨论】:

    标签: java xml sax stax


    【解决方案1】:

    据我了解,问题是您在解析之前不知道文档的格式。您可以使用委托模式。我假设您没有针对 DTD/XSD/etcetera 进行验证,并且 DefaultHandler 具有状态是可以的。

    public class DelegatingHandler extends DefaultHandler {
    
        private Map<String, DefaultHandler> saxHandlers;
        private DefaultHandler delegate = null;
    
        public DelegatingHandler(Map<String, DefaultHandler> delegates) {
            saxHandlers = delegates;
        }
    
        @Override
        public void startElement(String uri, String localName, String name,
                Attributes attributes) throws SAXException {
           if(delegate == null) {
               delegate = saxHandlers.get(name);
           }
           delegate.startElement(uri, localName, name, attributes);
        }
    
        @Override
        public void endElement(String uri, String localName, String name)
                throws SAXException {
            delegate.endElement(uri, localName, name);
        }
    
    //etcetera...
    

    【讨论】:

      【解决方案2】:

      你已经很好地解释了你想要做什么,但没有解释为什么。有几个 XML 框架可以简化 Java 对象与 XML 之间的编组和解组。

      最简单的是Commons Digester,我通常用它来解析配置文件。但是如果你想处理 Java 对象,那么你应该查看CastorJiBXJAXBXMLBeansXStream 或类似的东西。 Castor 或 JiBX 是我最喜欢的两个。

      【讨论】:

        【解决方案3】:

        我曾经尝试过 SAXParser,但一旦我找到 XStream,我就再也没有使用过它。使用 XStream,您可以创建 Java 对象并将它们转换为 XML。将它们发送过来并使用 XStream 重新创建对象。非常易于使用、快速并创建干净的 XML。

        无论哪种方式,您都必须知道要从 XML 文件中接收哪些数据。您可以通过不同的方式发送它们以了解要使用的解析器。或者有一个数据对象可以保存所有内容,但只填充一个结构(产品/商店/经理)。可能是这样的:

        public class DataStructure {
        
            List<ProductStructure> products;
        
            List<StoreStructure> stors;
        
            List<ManagerStructure> managers;
        
            ...
        
            public int getProductCount() {
                return products.lenght();
            }
        
            ...
        }
        

        并用 XStream 转换为 XML 发送过来然后重新创建对象。然后用它做你想做的事。

        【讨论】:

          【解决方案4】:

          查看XMLReader.setContentHandler() 的文档,上面写着:

          应用程序可以在解析过程中注册一个新的或不同的处理程序,并且 SAX 解析器必须立即开始使用新的处理程序。

          因此,您应该能够创建一个 SelectorContentHandler,它在第一个 startElement 事件之前使用事件,基于此更改 XML 阅读器上的 ContentHandler,并将第一个开始元素事件传递给新内容处理程序。您只需将XMLReader 传递给构造函数中的SelectorContentHandler。如果您需要所有将事件传递给特定于词汇表的内容处理程序,SelectorContentHandler 必须缓存这些事件然后传递它们,但在大多数情况下,这不是必需的。

          顺便说一句,我最近在几乎所有项目中都使用XOM 来处理 XML ja,到目前为止性能还不是问题。

          【讨论】:

            【解决方案5】:

            JAXB。 XML 绑定的 Java 体系结构。基本上,您创建一个定义 XML 布局的 xsd(我相信您也可以使用 DTD)。然后将 XSD 传递给 JAXB 编译器,编译器创建 Java 类来将 XML 文档编组和解组为 Java 对象。真的很简单。

            顺便说一句,jaxb 有命令行选项来指定要放置结果类的包名称等。

            【讨论】:

            • 发帖人已经表示他更喜欢使用像 SAX 这样的流解析器,因为预期的容量(每几分钟 1200 个)。此外,在他开始解析之前,他不知道任何单个 xml 的格式,因此基于 DTD 的解决方案无效!
            • 我同意 DTD 是一个很大的问题,但请记住,JAXB 也可以绑定子树,给定一个 Stax XMLStreamReader;此外,Java POJO 的内存要轻得多,通常占用的空间比原始 XML(或 DOM,它是 XML 本身占用的 3 到 5 倍!)要少得多。所以使用带有注释 POJO 的 JAXB 是非常合理的
            【解决方案6】:

            如果您想要更动态的处理,Stax 方法可能会比 Sax 更好。 这仍然是相当低级的;如果你想要更简单的方法,XStream 和 JAXB 是我的最爱。但它们确实需要非常严格的对象才能映射到。

            【讨论】:

              【解决方案7】:

              同意 StaxMan,有趣的是,他希望你使用 Stax。它是一个基于拉的解析器,而不是您当前使用的推。不过,这需要对您的代码进行一些重大更改。

              【讨论】:

                【解决方案8】:

                :-)

                是的,我对 Stax 有一些偏见。但正如我所说,数据绑定通常比流式解决方案更方便。但是,如果它是您想要的流式传输,并且不需要流水线(多个过滤阶段),Stax 比 SAX 更简单。

                还有一件事:与 XOM 一样好(wrt 替代品),如果您不处理“以文档为中心”的 xml(~= xhtml 页面、docbook、open office docs),树模型通常不是正确的选择)。 对于数据交换、配置文件等数据绑定更方便、更高效、更自然。对于这些用例,只需对像 DOM 这样的树模型说不。 所以,JAXB、XStream、JibX 都很好。或者,为了获得更多的口味,消化器、蓖麻、xmlbeans。

                【讨论】:

                  【解决方案9】:

                  VTD-XML 以作为重型 XML 处理的最佳 XML 处理技术而闻名。请参阅下面的参考以获取证明

                  http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-11-07
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多