这个Java程序如何运行?

时间:2011-04-04 15:48:45

标签: java xml saxparser

我在Java中阅读了DOMParserSAXParser。我对DOMParser毫不怀疑,人们比DOMParser更喜欢SAXParser,因为它需要内存。但是,我理解SAXParser的概念,我无法在此代码下使用:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ReadXMLFileSAX {

 public static void main(String args[]) {

  try {

     SAXParserFactory factory = SAXParserFactory.newInstance();
     SAXParser saxParser = factory.newSAXParser();

     DefaultHandler handler = new DefaultHandler() {

     boolean bfname = false;
     boolean blname = false;
     boolean bnname = false;
     boolean bsalary = false;

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

        System.out.println("Start Element :" + qName);

        if (qName.equalsIgnoreCase("FIRSTNAME")) {
           bfname = true;
        }

        if (qName.equalsIgnoreCase("LASTNAME")) {
           blname = true;
        }

        if (qName.equalsIgnoreCase("NICKNAME")) {
           bnname = true;
        }

        if (qName.equalsIgnoreCase("SALARY")) {
           bsalary = true;
        }

     }

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

          System.out.println("End Element :" + qName);

     }

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

         if (bfname) {
            System.out.println("First Name : "
                + new String(ch, start, length));
            bfname = false;
          }

          if (blname) {
              System.out.println("Last Name : "
                  + new String(ch, start, length));
              blname = false;
           }

          if (bnname) {
              System.out.println("Nick Name : "
                  + new String(ch, start, length));
              bnname = false;
           }

          if (bsalary) {
              System.out.println("Salary : "
                  + new String(ch, start, length));
              bsalary = false;
           }

        }

      };

      saxParser.parse("/home/anto/Groovy/Java/file.xml", handler);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

.xml文件是:

<?xml version="1.0"?>
<company>
    <staff>
        <firstname>yong</firstname>
        <lastname>mook kim</lastname>
        <nickname>mkyong</nickname>
        <salary>100000</salary>
    </staff>
    <staff>
        <firstname>low</firstname>
        <lastname>yin fong</lastname>
        <nickname>fong fong</nickname>
        <salary>200000</salary>
    </staff>
</company>

当我运行程序时,我得到这样的输出:

Start Element :company
Start Element :staff
Start Element :firstname
First Name : yong
End Element :firstname
Start Element :lastname
Last Name : mook kim
End Element :lastname
Start Element :nickname
Nick Name : mkyong
End Element :nickname
Start Element :salary
Salary : 100000
End Element :salary
End Element :staff
Start Element :staff
Start Element :firstname
First Name : low
End Element :firstname
Start Element :lastname
Last Name : yin fong
End Element :lastname
Start Element :nickname
Nick Name : fong fong
End Element :nickname
Start Element :salary
Salary : 200000
End Element :salary
End Element :staff
End Element :company

输出看起来非常好,但我对输出感到困惑!如何打印输出的顺序?哪个处理这个? 由于这是我第一次阅读SAX和DOM,我无法理解它,请帮助我。

7 个答案:

答案 0 :(得分:2)

SAX是基于事件的。因此,每次它看到开始标记,属性,标记内的字符,结束标记,......它都会调用处理程序的相应函数。

所以这里的流程是:

  1. 请参阅company代码,为其致电startElement
  2. 请参阅staff代码,为其致电startElement
  3. 请参阅firstname标记,为其调用startElement(设置布尔值)
  4. 查看字符(“yong”),为它们调用characters函数(查看设置了哪个布尔值并打印相应的消息并清除标记)
  5. 查看结束firstname代码,调用endElement函数
  6. ...

答案 1 :(得分:2)

通过调用saxParser.parse("/home/anto/Groovy/Java/file.xml", handler);,SAX Parser使用您实现的DefaultHandler(您作为参数传递的handler)进行XML解析。

SAX是基于事件的,当解析器遍历XML文档时会遇到这些事件。当SAX解析器遇到元素的开头,例如<firstname>时,它会调用startElement方法。然后,它遍历start元素的主体,并看到yong。由于它未包含在<>标记中,因此它被视为文本节点,因此它调用characters方法。如果有另一个XML元素,它将再次为新的XML元素调用startElement

最后,SAX Parser遍历,直到它看到结束元素</firstname>并调用endElement方法。

所有这三种方法startElementcharactersendElement均由开发人员(在您的情况下,您)实施。

不要忘记,SAX仅遍历您的XML文档。它不会记录哪个节点是哪个节点的父节点或子节点。

希望这有帮助!

答案 2 :(得分:0)

SAX解析器的强大之处在于它的事件。您需要做的就是覆盖/实现正确的方法,解析库上的onus就是按顺序调用事件。

答案 3 :(得分:0)

订单看起来很好。有什么问题?

如果您正在谈论开始和结束元素,那只会显示XML标记嵌套。你看到“公司”出现在“员工”之前,“员工”出现在“名字”之前。

最后,您在各个标签内部拥有数据。这就是为什么最后三行是:

End Element :salary
End Element :staff
End Element :company

因为它离开了工资,薪水是员工的最后一个要素,而且这是公司的最终员工。

答案 4 :(得分:0)

当解析器读取输入XML时,它会在每个开始标记上调用startElement,并在每个结束标记上调用endElement。如果解析器符合标记的内容,例如yong,则会调用characters

您发布的代码是使用状态变量bfnamebsalary等发布了当前正在解析哪个标记的代码。一旦调用characters,您的代码就会知道它所要求的实体 - 首先姓名,姓氏或工资,因此可以正确解读原始字符串。

因此,在编写SAX解析器时,实际上是在编写回调函数来跟踪XML中解析器的状态 - 它当前读取的是XML的哪一部分。

相反,在使用DOM解析器时,您可以将整个XML文档转换为树,因此您可以以任何您喜欢的方式从其根目录导航到节点,或向后 - 从节点导航到根目录。

答案 5 :(得分:0)

SAX解析器只迭代一个文档,一次一个字符。解析器的parse()方法采用Handler对象。当解析器遇到文档中的某些字符(“事件”)时,解析器会调用此对象的各种方法。因此,每次解析器遇到开始标记时,它都会调用Handler的startElement方法,当遇到结束标记时,它会调用endElement方法,依此类推。 DefaultHandler中的这些方法为空。由您来对这个类进行子类化并提供您自己的这些方法的实现(在上面的代码示例中,Defaulthandler已被匿名子类化)。

与DOM Parser不同,SAX Parser不构造元素 - 它只是在遇到开始和结束标记以及内容字符时触发各种处理程序方法。在这些方法中,由您提供逻辑,将结束标记映射到开始标记等等,这是条件语句在startElement和endElement方法中执行的操作。类变量blname等只是跟踪解析器当前所处的元素 - 这样您就可以知道与characters()方法传递的字符相关的内容。

答案 6 :(得分:0)

接近结尾时,您会注意到saxParser.parse()方法被赋予handler作为参数。处理程序是先前在代码中定义的DefaultHandler的实例。 SAXParser在解析XML文档时在处理程序上调用适当的方法。以下是DefaultHandlerSAXParser上的一些Javadoc(请参阅parse方法的文档)。解析XML文档并依次调用处理程序中的每个方法时,处理程序方法会打印出已处理的值。