sax解析xml方法_XML的方法–第2部分– SAX呢?

sax解析xml方法

第1部分介绍了采用不同方法进行XML解析的想法,并强调了XML不是STRING的观点。 而是一个可以使用字符串表示的面向对象的文档模型。 今天的博客使用我的 Pete的“完​​美披萨” 场景 继续了此讨论 。 如果你还记得的话,皮特只是把头撞在门上 并要求您增强系统,以便前台可以在单个XML消息中发送多个披萨的订单。 您知道您的简单字符串分析代码有缺陷,不会割裂芥末,因此您 在XML上使用了 Google 1 并提出了使用SAX的想法。

SAX或XML的简单API已经存在了很多年,据我所知,它最初是由David Megginson在千年之交之前开发的。 在那些日子里,您必须从David的个人网站下载Java版本的SAX。 在最终添加到Java Standard Edition 1.4中之前,它已发展为SAX项目

SAX是XML的流接口,这意味着使用SAX的应用程序从文档的顶部开始,以顺序的顺序接收到有关正在处理的XML文档的事件通知的元素和属性,并以关闭文档的结尾结束。根元素。 这意味着它在线性时间内处理XML非常高效,而对系统内存没有太多要求。

回到Pete ,您将努力工作,并提出以下基于SAX解析器的类:

public class PizzaParser {



  public List<PizzaOrder> order(InputStream xml) {



    PizzaContentHandler handler = new PizzaContentHandler();



    // do the parsing

    try {

      // Construct the parser by bolting together an XMLReader

      // and the ContentHandler

      XMLReader parser = XMLReaderFactory.createXMLReader();

      parser.setContentHandler(handler);



      // create an input source from the XML input stream

      InputSource source = new InputSource(xml);

      // Do the actual work

      parser.parse(source);



      return handler.getPizzaOrder();

    } catch (Exception ex) {

      throw new RuntimeException('Exception parsing xml message. Message: ' + ex.getMessage(), ex);

    }

  }



  static class PizzaOrder {



    private final String pizzaName;

    private final String base;

    private final String quantity;



    PizzaOrder(String pizzaName, String base, String quantity) {

      this.pizzaName = pizzaName;

      this.base = base;

      this.quantity = quantity;

    }



    public String getPizzaName() {

      return pizzaName;

    }



    public String getBase() {

      return base;

    }



    public String getQuantity() {

      return quantity;

    }

  }



  /**

   * Use this class the handle the SAX events

   */

  class PizzaContentHandler extends DefaultHandler {



    private String[] pizzaInfo;

    private int index;

    private List<PizzaOrder> outList;

    private boolean capture;



    /**

     * Set things up at the start of the document.

     */

    @Override

    public void startDocument() {

      outList = new ArrayList<PizzaOrder>();

    }



    /**

     * Handle the startElement event

     */

    @Override

    public void startElement(String uri, String localName, String qName, Attributes attributes) {



      capture = true;

      if ('pizzas'.equals(qName)) {

        capture = false;

      } else if ('pizza'.equals(qName)) {

        pizzaInfo = new String[3];

        capture = false;

      } else if ('name'.equals(qName)) {

        index = 0;

      } else if ('base'.equals(qName)) {

        index = 1;

      } else if ('quantity'.equals(qName)) {

        index = 2;

      }

    }



    /**

     * Handle the endElement event

     */

    @Override

    public void endElement(String uri, String localName, String qName) {



      if ('pizza'.equals(qName)) {

        outList.add(new PizzaOrder(pizzaInfo[0], pizzaInfo[1], pizzaInfo[2]));

      }

    }



    /**

     * Grab hold of incoming character data

     */

    @Override

    public void characters(char[] ch, int start, int length) {



      if (capture) {

        pizzaInfo[index] = new String(ch, start, length);

        capture = false;

      }

    }



    List<PizzaOrder> getPizzaOrder() {

      return outList;

    }

  }



}

这个博客不是在这里演示如何使用SAX,如果您看看周围有很多示例,但是让我们仔细看一下代码,首先要注意的是order(...)方法现在将输入流而不是字符串作为适合基于流的API:

public List<PizzaOrder> order(InputStream xml)

接下来要注意的是, PizzaParser使用嵌套类PizzaContentHandler ,该类扩展了SAX帮助程序类DefaultHandlerPizzaContentHandler类将捕获PizzaOrder bean的列表,并将它们传递回封闭类,以返回给调用者。 这意味着要掌握SAX事件,您需要做的就是重写处理程序方法,例如startElement(...)endElement(...)等。
如果仔细看一下代码,您会发现它非常复杂。 它要做的就是创建一个输出列表,但是有多个if()语句,临时数组和布尔开关用于从文档的正确位置获取正确的信息。 这是SAX的缺点:它的复杂性给程序员带来了更多负担,并使您的代码更容易出错。

但是,它比以前的基于字符串的尝试更具弹性,如下面的单元测试所示:

public class PizzaParserTest {



  private static final String ORDER_XML = //

  '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n' + //

      '<pizza>\n' + // 8

      '    <name>Capricciosa</name>\n' + //

      '    <base>thin</base>\n' + //

      '    <quantity>2</quantity>\n' + //

      '</pizza>\n';



  private static final String ORDER_XML_2 = //

  '<?xml version=\'1.0\' encoding=\'UTF-8\'?><pizza><name>Capricciosa</name><base>thin</base><quantity>2</quantity></pizza>';



  private static final String ORDER_XML_3 = //

  '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n' + //

      '<pizzas>\n' + //

      '    <pizza>\n' + //

      '        <name>Capricciosa</name>\n' + //

      '        <base>thin</base>\n' + //

      '        <quantity>2</quantity>\n' + //

      '    </pizza>\n' + //

      '    <pizza>\n' + //

      '        <name>Margherita</name>\n' + //

      '        <base>thin</base>\n' + //

      '        <quantity>1</quantity>\n' + //

      '    </pizza>\n' + //

      '</pizzas>';



  private PizzaParser instance;



  @Before

  public void setUp() {

    instance = new PizzaParser();

  }



  @Test

  public void readOrderFromXML() {



    List<PizzaOrder> results = instance.order(new ByteArrayInputStream(ORDER_XML.getBytes()));



    assertEquals(1, results.size());



    PizzaOrder result = results.get(0);

    assertEquals('Capricciosa', result.getPizzaName());

    assertEquals('thin', result.getBase());

    assertEquals('2', result.getQuantity());

  }



  @Test

  public void readOrderFromModifiedXML() {



    List<PizzaOrder> results = instance.order(new ByteArrayInputStream(ORDER_XML_2.getBytes()));



    assertEquals(1, results.size());



    PizzaOrder result = results.get(0);

    assertEquals('Capricciosa', result.getPizzaName());

    assertEquals('thin', result.getBase());

    assertEquals('2', result.getQuantity());

  }



  @Test

  public void readOrderForMultiplePizza() {



    List<PizzaOrder> results = instance.order(new ByteArrayInputStream(ORDER_XML_3.getBytes()));



    PizzaOrder result = results.get(0);

    assertEquals('Capricciosa', result.getPizzaName());

    assertEquals('thin', result.getBase());

    assertEquals('2', result.getQuantity());



    result = results.get(1);

    assertEquals('Margherita', result.getPizzaName());

    assertEquals('thin', result.getBase());

    assertEquals('1', result.getQuantity());

  }

}

这些测试演示了处理带有和不带有空格(解决昨天的问题)的XML消息以及包含多个比萨饼订单的消息的场景。

一切都很好,但是Pete的宏伟构想正在实现。 现在,他通过遍布世界各地的多个厨房和在线业务扩展到全世界。 皮特(Pete)聘请了一些时髦的业务顾问,他们创建了一个新的比萨订单XML模式并将其与他们现有的客户模式相结合。 这已放入您的电子邮件收件箱,您想知道下一步该怎么做...

1其他搜索引擎可用。

可从GitHub上获得源代码:

git://github.com/roghughe/captaindebug.git

继续阅读本系列的第3部分

参考: XML的方法–第2部分– SAX呢? 来自我们的JCG合作伙伴 Roger Hughes,来自Captain Debug的Blog博客。


翻译自: https://www.javacodegeeks.com/2012/07/approaches-to-xml-part-2-what-about-sax.html

sax解析xml方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值