SAX和DOM有什么区别?

时间:2011-07-26 10:33:22

标签: xml-parsing saxparser domparser

我阅读了一些关于 XML 解析器的文章,并且遇到了 SAX DOM

SAX 是基于事件的, DOM 是树模型 - 我不明白这些概念之间的差异。

根据我的理解,基于事件意味着节点会发生某种事件。就像当单击特定节点时,它将给出所有子节点,而不是同时加载所有节点。但是在 DOM 解析的情况下,它将加载所有节点并生成树模型。

我的理解是否正确?

请纠正我如果我错了或以更简单的方式向我解释基于事件和树模型。

10 个答案:

答案 0 :(得分:291)

嗯,你很亲密。

在SAX中,当解析 XML时会触发事件。当解析器解析XML并遇到标记开始(例如<something>)时,它会触发tagStarted事件(事件的实际名称可能不同)。类似地,当解析(</something>)时满足标记的结尾时,它会触发tagEnded。使用SAX解析器意味着您需要处理这些事件并理解每个事件返回的数据。

在DOM中,解析时没有触发事件。解析整个XML并生成并返回DOM树(XML中的节点)。解析后,用户可以导航树以访问先前嵌入在XML中各个节点中的各种数据。

通常,DOM更易于使用,但在开始使用之前需要解析整个XML。

答案 1 :(得分:92)

只需几句话......

SAX S 实现 A PI X ML):是基于流的处理器。你随时只在内存中占有很小的一部分,你可以通过为tagStarted()等事件实现回调代码来“嗅探”XML流。它几乎不使用内存,但你不能做“DOM”的东西,比如使用xpath或遍历树。

DOM D ocument O bject M odel):将整个内容加载到内存中 - 这是一个巨大的内存猪。你甚至可以用中等大小的文件来记忆。但是你可以使用xpath并遍历树等。

答案 2 :(得分:59)

这里用简单的话说:

<强> DOM

  • 树模型解析器(基于对象)(节点树)。

  • DOM将文件加载到内存中,然后解析文件。

  • 由于在解析之前加载整个XML文件,因此存在内存限制。

  • DOM是读写的(可以插入或删除节点)。

  • 如果XML内容很小,则更喜欢DOM解析器。

  • 可以进行向后和向前搜索以搜索标签和评估 标签内的信息。这样便于导航。

  • 在运行时较慢。

<强> SAX

  • 基于事件的解析器(事件序列)。

  • SAX在读取文件时对其进行解析,即逐节点解析。

  • 没有内存限制,因为它不会将XML内容存储在内存中。

  • SAX是只读的,即无法插入或删除节点。

  • 当内存容量很大时使用SAX解析器。

  • SAX从上到下读取XML文件,无法向后导航。

  • 在运行时更快。

答案 3 :(得分:37)

您对基于DOM的模型的理解是正确的。 XML文件将作为整体加载,其所有内容将构建为文档所代表的树的内存表示形式。这可能耗费时间和内存,具体取决于输入文件的大小。这种方法的好处是您可以轻松查询文档的任何部分,并自由地操作树中的所有节点。

DOM方法通常用于小型XML结构(小型结构取决于您的平台具有多少马力和内存),一旦加载,可能需要以不同方式进行修改和查询。

另一方面,SAX旨在处理几乎任何大小的XML输入。在确定文档结构并为所有节点,属性等准备大量对象时,而不是XML框架为您做了艰苦的工作,SAX完全不需要你。

它基本上做的是从顶部读取输入并调用您在发生某些“事件”时提供的回调方法。事件可能会触及开始标记,标记中的属性,在元素中查找文本或遇到结束标记。

SAX顽固地阅读输入并告诉你它以这种方式看到了什么。您需要维护所需的所有状态信息。通常这意味着你将构建某种状态机。

虽然这种XML处理方法更加繁琐,但它也非常强大。想象一下,您只想从博客Feed中提取新闻文章的标题。如果您使用DOM读取此XML,它会将所有文章内容,XML中包含的所有图像等加载到内存中,即使您甚至对它都不感兴趣。

使用SAX,只要调用“startTag”事件方法,就可以检查元素名称是否为(例如)“title”。如果是这样,您知道您需要添加下一个“elementText”事件为您提供的任何内容。当您收到“endTag”事件调用时,再次检查这是否是“标题”的结束元素。之后,您只需忽略所有其他元素,直到输入结束,或者另一个名为“title”的“startTag”出现。等等...

您可以通过这种方式读取兆字节和兆字节的XML,只需提取您需要的少量数据。

这种方法的消极方面当然是,您需要自己做更多的簿记,具体取决于您需要提取的数据以及XML结构的复杂程度。此外,您自然无法修改XML树的结构,因为您从来没有将它作为一个整体。

因此,一般而言,SAX适合于通过特定的“查询”来收集您收到的潜在大量数据,但不需要修改,而DOM更倾向于为您提供更改结构和内容的完全灵活性,以牺牲更高的资源需求为代价。

答案 4 :(得分:16)

你在比较苹果和梨。 SAX是一个解析序列化DOM结构的解析器。有许多不同的解析器,“基于事件”指的是解析方法。

也许是一个小小的回顾:

  • 文档对象模型(DOM)是一个抽象数据模型,它描述了一个基于树的分层文档结构;文档树由节点组成,即元素,属性和文本节点(以及其他一些节点)。节点有父母,兄弟姐妹和孩子,可以遍历等等,这些都是你习惯做的JavaScript(顺便提一下,与DOM无关)。

  • DOM结构可以序列化,即使用HTML或XML等标记语言写入文件。因此,HTML或XML文件包含抽象文档树的“写出”或“扁平化”版本。

  • 对于要从文件中操作甚至显示DOM树的计算机,它必须反序列化解析,文件并重建在记忆中的抽象树。这就是解析的地方。

现在我们来看解析器的本质。解析的一种方法是读入整个文档并在内存中递归地构建树结构,最后将整个结果公开给用户。 (我想你可以将这些解析器称为“DOM解析器”。)这对用户来说非常方便(我认为这是PHP的XML解析器所做的),但是它存在可扩展性问题,并且对于大型文档而言变得非常昂贵。

另一方面,由SAX完成的基于事件的解析会线性查看文件,并在遇到文件时简单地对用户进行回调结构化的数据,例如“this element started”,“that elements ends”,“some text here”等等。这样做的好处是它可以永远持续而不用担心输入文件的大小,但是它更低-level因为它要求用户完成所有实际的处理工作(通过提供回调)。要返回原始问题,术语“基于事件”是指解析器在遍历XML文件时引发的解析事件

Wikipedia article有很多关于SAX解析阶段的细节。

答案 5 :(得分:9)

我将为这个问题提供一般的Q&amp; A面向答案:

回答问题

  

为什么我们需要XML解析器?

我们需要XML解析器,因为我们不想从头开始在我们的应用程序中执行所有操作,而且我们需要一些&#34; helper&#34;程序或图书馆做一些非常低级但对我们来说非常必要的事情。这些低级但必要的事情包括检查格式良好,根据其DTD或模式验证文档(仅用于验证解析器),解析字符引用,理解CDATA部分等。 XML解析器就是这样的&#34;帮助&#34;他们将完成所有这些工作。使用XML解析器,我们可以避免许多这些复杂性,我们可以专注于通过解析器实现的API在高级编程,从而提高编程效率。

  

哪一个更好,SAX还是DOM?

SAX和DOM解析器都有其优点和缺点。哪一个更好应该取决于您的应用程序的特点(请参阅下面的一些问题)。

  

哪种解析器可以获得更好的速度,DOM或SAX解析器?

SAX解析器可以获得更好的速度。

  

基于树的API与基于事件的API之间的区别是什么?

基于树的API以树结构为中心,因此在树的组件(DOM文档)上提供接口,例如Document接口,Node接口,NodeList接口,Element接口,Attr接口等。然而,相比之下,基于事件的API提供了处理程序上的接口。有四个处理程序接口,ContentHandler接口,DTDHandler接口,EntityResolver接口和ErrorHandler接口。

  

DOM解析器和SAX解析器之间有什么区别?

DOM解析器和SAX解析器以不同的方式工作:

  • DOM解析器从输入中在内存中创建树结构 文档,然后等待客户端的请求。但是SAX解析器 不会创建任何内部结构。相反,它需要 输入文档的组件出现为事件,并告诉 客户端读取输入文档时读取的内容。 A

  • DOM解析器始终为整个客户端应用程序提供服务 无论客户实际需要多少文件。但是一个 SAX解析器始终只为部分服务客户端应用程序 在任何给定时间的文件。

  • 使用DOM解析器,方法调用 客户端应用程序必须是显式的,并形成一种链。但 使用SAX,某些特定方法(通常由客户覆盖)将会 以被调用的方式自动(隐式)调用 &#34;回调&#34;当某些事件发生时。这些方法没有 虽然我们可以调用它们,但是客户端会明确调用它们 明确。
  

我们如何决定哪个解析器好?

理想情况下,一个好的解析器应该快速(节省时间),节省空间,功能丰富且易于使用。但实际上,没有一个主解析器同时具有所有这些功能。例如,DOM Parser功能丰富(因为它在内存中创建了一个DOM树,允许您重复访问文档的任何部分并允许您修改DOM树),但是当文档很大时,它的空间效率很低,学习如何使用它需要一点点时间。但是,SAX Parser在输入大文档时更节省空间(因为它不会创建内部结构)。而且,它比DOM Parser运行得更快,更容易学习,因为它的API非常简单。但从功能的角度来看,它提供的功能较少,这意味着用户自己必须处理更多,例如创建自己的数据结构。顺便问一下,什么是好的解析器?我认为答案实际上取决于您的应用程序的特征。

  

使用SAX解析器的实际应用是什么?   比使用DOM解析器更有利,反之亦然?什么是平常的   DOM解析器和SAX解析器的应用程序?

在以下情况下,使用SAX解析器比使用DOM解析器更有优势。

  • 输入文档对于可用内存而言太大(实际上在这种情况下,SAX是您唯一的选择)
  • 您可以在小的连续输入块中处理文档。在完成有用的工作之前,您不需要整个文档
  • 您只想使用解析器提取感兴趣的信息,您的所有计算将完全基于您自己创建的数据结构。实际上,在我们的大多数应用程序中,我们创建了自己的数据结构,这些结构通常不像DOM树那么复杂。从这个意义上讲,我认为,使用DOM解析器的可能性小于使用SAX解析器的可能性。

在以下情况下,使用DOM解析器比使用SAX解析器更有优势。

  • 您的应用程序需要同时广泛访问文档的各个部分。
  • 您的应用程序可能使用的内部数据结构几乎与文档本身一样复杂。
  • 您的申请必须重复修改文档。
  • 您的应用程序必须通过多次方法调用将文档存储大量时间。

示例(使用DOM解析器或SAX解析器?):

假设教师有一份XML文档,其中包含学生的所有个人信息以及他的学生在课堂上所做的分数,他现在正在为使用应用程序的学生分配最终成绩。他想要制作的是SSN和成绩列表。我们还假设在他的应用程序中,教师不使用数组等数据结构来存储学生的个人信息和积分。 如果教师决定给那些平均成绩达到或高于平均成绩的学生,并将B给予其他人,那么他最好在他的应用程序中使用DOM解析器。原因是他无法知道整个文档处理之前的平均等级是多少。他在申请中可能需要做的是首先要透过所有学生的观察。得分并计算平均值,然后再次查看文档,并通过比较他获得的积分与班级平均值,为每个学生分配最终成绩。 但是,如果教师采用这样的评分政策,得到90分或以上的学生被分配A而其他人被分配B,那么他可能更好地使用SAX解析器。原因是,为每个学生分配最终成绩,他不需要等待处理整个文档。一旦SAX解析器读取该学生的成绩,他就可以立即为学生分配成绩。 在上面的分析中,我们假设教师没有创建自己的数据结构。如果他创建自己的数据结构,例如存储SSN的字符串数组和存储点的整数数组,该怎么办?在这种情况下,我认为SAX是一个更好的选择,在此之前既可以节省内存和时间,又可以完成工作。 那么,还有一个关于这个例子的考虑。如果教师想要做的不是打印列表,而是保存原始文档并更新每个学生的成绩怎么办?在这种情况下,无论他采用何种评分策略,DOM解析器都应该是更好的选择。他不需要创建自己的任何数据结构。他需要做的是首先修改DOM树(即,将值设置为&#39; grade&#39;节点),然后保存整个修改后的树。如果他选择使用SAX解析器而不是DOM解析器,那么在这种情况下,他必须创建一个几乎与DOM树一样复杂的数据结构,然后才能完成工作。

示例

  

问题陈述:编写一个Java程序来解压所有   有关作为给定XML文档中的元素的圆的信息。   我们假设每个圆元素有三个子元素(即x,y   和半径)以及颜色属性。给出了一份样本文件   下面:

<?xml version="1.0"?> 
<!DOCTYPE shapes [
<!ELEMENT shapes (circle)*>
<!ELEMENT circle (x,y,radius)>
<!ELEMENT x (#PCDATA)>
<!ELEMENT y (#PCDATA)>
<!ELEMENT radius (#PCDATA)>
<!ATTLIST circle color CDATA #IMPLIED>
]>

<shapes> 
          <circle color="BLUE"> 
                <x>20</x>
                <y>20</y>
                <radius>20</radius> 
          </circle>
          <circle color="RED" >
                <x>40</x>
                <y>40</y>
                <radius>20</radius> 
          </circle>
</shapes> 

使用DOMparser编程

import java.io.*;
import org.w3c.dom.*;
import org.apache.xerces.parsers.DOMParser;


public class shapes_DOM {
   static int numberOfCircles = 0;   // total number of circles seen
   static int x[] = new int[1000];   // X-coordinates of the centers
   static int y[] = new int[1000];   // Y-coordinates of the centers  
   static int r[] = new int[1000];   // radius of the circle
   static String color[] = new String[1000];  // colors of the circles 

   public static void main(String[] args) {   

      try{
         // create a DOMParser
         DOMParser parser=new DOMParser();
         parser.parse(args[0]);

         // get the DOM Document object
         Document doc=parser.getDocument();

         // get all the circle nodes
         NodeList nodelist = doc.getElementsByTagName("circle");
         numberOfCircles =  nodelist.getLength();

         // retrieve all info about the circles
         for(int i=0; i<nodelist.getLength(); i++) {

            // get one circle node
            Node node = nodelist.item(i);

            // get the color attribute 
            NamedNodeMap attrs = node.getAttributes();
            if(attrs.getLength() > 0)
               color[i]=(String)attrs.getNamedItem("color").getNodeValue();

            // get the child nodes of a circle node 
            NodeList childnodelist = node.getChildNodes();

            // get the x and y value 
            for(int j=0; j<childnodelist.getLength(); j++) {
               Node childnode = childnodelist.item(j);
               Node textnode = childnode.getFirstChild();//the only text node
               String childnodename=childnode.getNodeName(); 
               if(childnodename.equals("x")) 
                  x[i]= Integer.parseInt(textnode.getNodeValue().trim());
               else if(childnodename.equals("y")) 
                  y[i]= Integer.parseInt(textnode.getNodeValue().trim());
               else if(childnodename.equals("radius")) 
                  r[i]= Integer.parseInt(textnode.getNodeValue().trim());
            }

         }

         // print the result
         System.out.println("circles="+numberOfCircles);
         for(int i=0;i<numberOfCircles;i++) {
             String line="";
             line=line+"(x="+x[i]+",y="+y[i]+",r="+r[i]+",color="+color[i]+")";
             System.out.println(line);
         }

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

    }

}

使用SAXparser编程

import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.xerces.parsers.SAXParser;


public class shapes_SAX extends DefaultHandler {

   static int numberOfCircles = 0;   // total number of circles seen
   static int x[] = new int[1000];   // X-coordinates of the centers
   static int y[] = new int[1000];   // Y-coordinates of the centers
   static int r[] = new int[1000];   // radius of the circle
   static String color[] = new String[1000];  // colors of the circles

   static int flagX=0;    //to remember what element has occurred
   static int flagY=0;    //to remember what element has occurred
   static int flagR=0;    //to remember what element has occurred

   // main method 
   public static void main(String[] args) {   
      try{
         shapes_SAX SAXHandler = new shapes_SAX (); // an instance of this class
         SAXParser parser=new SAXParser();          // create a SAXParser object 
         parser.setContentHandler(SAXHandler);      // register with the ContentHandler 
         parser.parse(args[0]);
      }  catch (Exception e) {e.printStackTrace(System.err);}  // catch exeptions
   }

   // override the startElement() method
   public void startElement(String uri, String localName, 
                       String rawName, Attributes attributes) {
         if(rawName.equals("circle"))                      // if a circle element is seen
            color[numberOfCircles]=attributes.getValue("color");  // get the color attribute 

         else if(rawName.equals("x"))      // if a x element is seen set the flag as 1 
            flagX=1;
         else if(rawName.equals("y"))      // if a y element is seen set the flag as 2
            flagY=1;
         else if(rawName.equals("radius")) // if a radius element is seen set the flag as 3 
            flagR=1;
   }

   // override the endElement() method
   public void endElement(String uri, String localName, String rawName) {
         // in this example we do not need to do anything else here
         if(rawName.equals("circle"))                       // if a circle element is ended 
            numberOfCircles +=  1;                          // increment the counter 
   }

   // override the characters() method
   public void characters(char characters[], int start, int length) {
         String characterData = 
             (new String(characters,start,length)).trim(); // get the text

         if(flagX==1) {        // indicate this text is for <x> element 
             x[numberOfCircles] = Integer.parseInt(characterData);
             flagX=0;
         }
         else if(flagY==1) {  // indicate this text is for <y> element 
             y[numberOfCircles] = Integer.parseInt(characterData);
             flagY=0;
         }
         else if(flagR==1) {  // indicate this text is for <radius> element 
             r[numberOfCircles] = Integer.parseInt(characterData);
             flagR=0;
         }
   }

   // override the endDocument() method
   public void endDocument() {
         // when the end of document is seen, just print the circle info 
         System.out.println("circles="+numberOfCircles);
         for(int i=0;i<numberOfCircles;i++) {
             String line="";
             line=line+"(x="+x[i]+",y="+y[i]+",r="+r[i]+",color="+color[i]+")";
             System.out.println(line);
         }
   }


}

答案 6 :(得分:6)

实际上:book.xml

<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
</bookstore>
  • DOM在内存中将xml文档显示为以下树结构
  • DOM是W3C标准。
  • DOM解析器适用于文档对象模型。
  • DOM占用更多内存,首选小型XML文档
  • DOM易于向前或向后导航。

enter image description here

  • SAX将xml文档显示为基于事件的,例如start element:abcend element:abc
  • SAX不是W3C标准,它是由开发人员开发的。
  • SAX不使用内存,首选大型XML文档。
  • 无法向后导航,因为它会按顺序处理文档。
  • 事件发生在一个节点/元素上,它给出了所有子节点(拉丁语nodus,'knot')。

This XML document, when passed through a SAX parser, will generate a sequence of events like the following

start element: bookstore
start element: book with an attribute category equal to cooking
start element: title with an attribute lang equal to en
Text node, with data equal to Everyday Italian
....
end element: title
.....
end element: book
end element: bookstore

答案 7 :(得分:3)

DOM代表文档对象模型,它将XML文档表示为树格式,每个元素代表树分支。 DOM Parser创建XML文件的In Memory树表示然后解析它,因此它需要更多内存,并且建议增加DOM解析器的堆大小以避免Java.lang.OutOfMemoryError:java堆空间。如果XML文件很小,使用DOM解析器解析XML文件的速度非常快,但是如果您尝试使用DOM解析器读取大型XML文件,则可能需要很长时间才能完全加载它,甚至可能无法完全加载它创建XML Dom Tree需要大量内存。 Java提供了对DOM Parsing的支持,您可以使用DOM解析器解析Java中的XML文件。 DOM类在w3c.dom包中,而DOM Parser for Java在JAXP(Java API for XML Parsing)包中。

Java中的SAX XML解析器

SAX代表XML解析的简单API。这是一个基于事件的XML Parsing,它逐步解析XML文件,非常适合大型XML文件。 SAX XML Parser在遇到打开标记,元素或属性时触发事件,并且解析相应地工作。建议使用SAX XML解析器来解析Java中的大型xml文件,因为它不需要在Java中加载整个XML文件,并且它可以读取一小部分的大型XML文件。 Java提供了对SAX解析器的支持,您可以使用SAX Parser解析Java中的任何xml文件,我已经介绍了使用SAX Parser读取xml文件的示例。在java中使用SAX Parser的一个缺点是,使用SAX Parser在Java中读取XML文件需要比DOM Parser更多的代码。

DOM和SAX XML Parser之间的区别

以下是Java解析器和Java中的SAX解析器之间的高级别差异:

1)DOM解析器在内存中加载整个xml文档,而SAX只在内存中加载一小部分XML文件。

2)DOM解析器比SAX更快,因为它可以访问内存中的整个XML文档。

3)Java中的SAX解析器比DOM Parser更适合大型XML文件,因为它不需要太多内存。

4)DOM解析器适用于文档对象模型,而SAX是基于事件的xml解析器。

了解详情:http://javarevisited.blogspot.com/2011/12/difference-between-dom-and-sax-parsers.html#ixzz2uz1bJQqZ

答案 8 :(得分:2)

SAX和DOM都用于解析XML文档。两者都有优点和缺点,可以根据情况在我们的编程中使用

SAX:

  1. 逐节点解析

  2. 不将XML存储在内存中

  3. 我们无法插入或删除节点

  4. 自上而下遍历

  5. DOM

    1. 在处理

    2. 之前将整个XML文档存储到内存中
    3. 占用更多内存

    4. 我们可以插入或删除节点

    5. 向任何方向移动。

    6. 如果我们需要找到一个节点而不需要插入或删除,我们可以使用SAX本身,否则DOM提供了更多内存。

答案 9 :(得分:1)

1)DOM解析器在内存中加载整个XML文档,而SAX只在内存中加载一小部分XML文件。

2)DOM解析器比SAX更快,因为它可以访问内存中的整个XML文档。

3)Java中的SAX解析器比DOM Parser更适合大型XML文件,因为它不需要太多内存。

4)DOM解析器适用于文档对象模型,而SAX是基于事件的XML解析器。

了解详情:http://javarevisited.blogspot.com/2011/12/difference-between-dom-and-sax-parsers.html#ixzz498y3vPFR