我们将如何使用Java处理各种XML文档?

时间:2020-03-05 18:43:58  来源:igfitidea点击:

我正在寻找使用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文档的最佳方法是什么?我曾尝试在较一般的帖子中提问……但是,我认为我太含糊了。为了提高速度和效率,我从未真正看过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>

manager.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>

解决方案

回答

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

顺便说一句,jaxb有命令行选项,以指定我们要在其中放置结果类的包名称,以此类推。

回答

我们已经很好地解释了我们想做什么,但没有解释原因。有几种XML框架可简化Java对象与XML之间的编组和解组。

最简单的是Commons Digester,我通常使用它来解析配置文件。但是,如果要处理Java对象,则应查看Castor,JiBX,JAXB,XMLBeans,XStream或者类似的对象。 Castor或者JiBX是我的两个最爱。

回答

我曾经尝试过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发送过来,然后重新创建对象。然后用它来做你想做的。

回答

据我了解,问题在于我们在解析之前不知道文档的格式。我们可以使用委托模式。我假设我们不针对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...

回答

请参阅XMLReader.setContentHandler()的文档,其中显示:

Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin using the new handler immediately.

因此,我们应该能够创建一个使用SelectorContentHandler的事件,该事件将消耗事件直到第一个startElement事件为止,基于此,将更改XML阅读器上的ContentHandler并将第一个start元素事件传递给新的内容处理程序。我们只需要将XMLReader传递给构造函数中的SelectorContentHandler即可。如果我们需要将所有事件传递给特定于词汇的内容处理程序,则SelectorContentHandler必须先缓存事件,然后将其传递,但​​是在大多数情况下不需要这样做。

附带说明一下,我最近在几乎所有项目中都使用XOM来处理XML ja,到目前为止,性能并不是问题。

回答

如果我们需要更多动态处理,则Stax方法可能比Sax更好。
那还是很低级的。如果我们想要更简单的方法,XStream和JAXB是我的最爱。但是它们确实需要相当严格的对象才能映射到。

回答

同意StaxMan,有趣的是,他希望我们使用Stax。这是一个基于请求的解析器​​,而不是我们当前使用的请求。但是,这将需要对代码进行一些重大更改。

回答

:-)

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

还有一件事:与XOM一样好(可以替代),如果不处理"以文档为中心"的xml(〜= xhtml页面,docbook,开放式办公室文档),则通常不适合使用Tree Model。
对于数据交换,配置文件等,数据绑定更方便,更高效,更自然。对于这些用例,只需对DOM之类的树模型说不即可。
因此,JAXB,XStream,JibX都不错。或者,为了获得更多的口味,请使用蒸煮器,蓖麻和xmlbeans。