开发那点事系列三 - 由XML解析引起的API设计思考
谈起XML解析,大家可能第一反应是DOM,SAX模型。没错,在Java领域,无论是Dom4j, Jdom,还是XOM,其底层都会依赖具体的解析器引擎(Crimson or Xerces)去做事,具体的实现后面会有文章陆续探究。今天写这篇文章的主要目的是想和大家分享自己使用Java SE6的StAX API的一些感受,尤其是对其API的设计理念的一个思考,没多少文字,主要是一些启发性的东东。当然,在你继续浏览之前,希望能熟练掌握以下类库,有助于更好的和我产生共鸣,哈哈:
SAX | StAX | DOM | XSLT |
---|---|---|---|
javax.xml.parsers | javax.xml.stream | javax.xml.parsers | javax.xml.transform |
|
javax.xml.stream.events |
|
javax.xml.transform.dom |
|
javax.xml.stream.util |
|
javax.xml.transform.sax |
|
|
|
javax.xml.transform.stax |
|
|
|
javax.xml.transform.stream |
技术使用论&技术创造论,无论你秉持哪种观点,原理性的、设计性的思维多培养培养,总归没有错的。在对Sun的JAX-× API深度理解的基础上,希望能抛砖引玉,引发XML API设计上的思考。言归正传吧,当我们读过一些资料(尤其是我后面列出的文献资料)过后,我们都会了解到Stax和SAX的不同之处:基于流的两种不同模型的实现- Push和Pull。那么什么是pull,什么又是push,到底哪种好?一句话概括一下(示例代码如下):Push模型要靠回调或者观察者模式运作,而Pull模型靠的是迭代器,外加Visitor模式的Filter机制(一种不错的事件处理链模式)。
SAX(Application code registers a callback, which the SAX parser invokes as it reads the XML:)
FileInputStream fis = new FileInputStream(file); XMLReader saxXmlReader = XMLReaderFactory.createXMLReader(); // Create callback handler DefaultHandler handler = new DefaultHandler() { public void startElement(String uri, String localName, String qName, Attributes attributes) { // do something with element } }; // register hander saxXmlReader.setContentHandler(handler); saxXmlReader.setErrorHandler(handler); // control passed to parser... saxXmlReader.parse(new InputSource(fis));
StAX(Application code controls parsing directly by iterating over the document using the StAX stream reader)
FileInputStream fis = new FileInputStream(file); XMLInputFactory factory = (XMLInputFactory)XMLInputFactory.newInstance(); XMLStreamReader staxXmlReader = (XMLStreamReader) factory.createXMLStreamReader(fis); for (int event = staxXmlReader.next(); event != XMLStreamConstants.END_DOCUMENT; event = staxXmlReader.next()) { switch (event) { case XMLStreamConstants.START_DOCUMENT: // do something with element, such as :System.out.println("Start document " + staxXmlReader.getLocalName()); break; case XMLStreamConstants.START_ELEMENT: // do something with element, such as :System.out.println("Start element " + staxXmlReader.getLocalName()); // do something with element, such as :System.out.println("Element text " + staxXmlReader.getElementText()); break; case XMLStreamConstants.END_ELEMENT: // do something with element break; default: // do something with element break; }}
看似朴实的设计思路,却衍生出很多思考。Spring中充满了钩子回调函数(类似preXXXHandler/Processor,postXXXHandler/Processor),为什么不做成Listener 的API?HtmlParser中也充满了Visitor模式,比起Handler机制,灵活在哪?为什么说StAX既保证了运行时效率,又把持了元素的上下文状态。。。诸如此类的问题,在设计我们自己的框架API时,无不需要慎重考虑~
参考文献:
1.https://www.ibm.com/developerworks/cn/java/j-lo-jse6/
2.https://www.ibm.com/developerworks/cn/xml/x-stax1.html
3.https://www.ibm.com/developerworks/library/x-stax1/index.html
4.https://www.jcp.org/en/jsr/detail?id=173
5.https://www.ibm.com/developerworks/cn/xml/x-jaxp/
6.https://www.edankert.com/jaxpimplementations.html
7.https://dom4j.sourceforge.net/dom4j-1.6.1/benchmarks/xpath/index.html
最后更新:2017-04-02 22:16:36