SAX和DOM有什么区别?

use*_*967 237 saxparser xml-parsing domparser

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

SAX是基于事件的,DOM是树模型 - 我不理解这些概念之间的差异.

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

我的理解是否正确?

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

spa*_*mat 299

嗯,你很亲密.

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

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

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

  • +1 - 澄清:使用适合RAM的较小文件的DOM解析器.对不适合的大型文件使用SAX解析器. (131认同)
  • 它只会解析.您必须自己(通过状态机或其他方式)维护此类信息.更有理由使用DOM解析器(如果资源允许):-). (4认同)
  • 加载 40m 大小的 excel,使用 SAX 解析器时使用 200m 内存,但使用 DOM 解析器时使用 9g 内存。 (2认同)

Boh*_*ian 95

只需几句话......

SAX(小号 imple 用于PI X ML):是基于数据流的处理器.你随时只在内存中占有很小的一部分,你可以通过实现类似事件的回调代码来"嗅探"XML流tagStarted().它几乎不使用任何内存,但你不能做"DOM"的东西,比如使用xpath或traverse树木.

DOM(d ocument Ø bject 中号奥德尔):你加载整个事情到内存-这是一个巨大的内存消耗.你甚至可以用中等大小的文件来记忆.但是你可以使用xpath并遍历树等.


小智 63

这里用简单的话说:

DOM

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

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

  • 具有内存限制,因为它在解析之前加载整个XML文件.

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

  • 如果XML内容很小,那么更喜欢DOM解析器.

  • 可以使用向后和向前搜索来搜索标签并评估标签内的信息.这样便于导航.

  • 运行时较慢.

SAX

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

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

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

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

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

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

  • 在运行时更快.


Dan*_*ler 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更倾向于为您提供更改结构和内容的完全灵活性,代价是更高的资源需求.


Ker*_* SB 16

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

也许是一个小小的回顾:

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

  • 可以使用诸如HTML或XML之类的标记语言将DOM结构序列化,即写入文件.因此,HTML或XML文件包含抽象文档树的"写出"或"扁平化"版本.

  • 对于计算机来操作甚至显示文件中的DOM树,它必须反序列化解析文件并重构内存中的抽象树.这是解析的地方.

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

在另一方面,基于事件的解析,如SAX完成,着眼于线性文件,只是使回调到用户每当遇到数据的结构件,如"这个元素开始","这个元素结束" "这里有一些文字",等等.这样做的好处是它可以永远持续而不用考虑输入文件的大小,但它更低级别,因为它要求用户完成所有实际的处理工作(通过提供回调).要回到原始问题,术语"基于事件"是指解析器在遍历XML文件时引发的事件.

维基百科的文章对SAX解析的阶段,许多细节.


Hum*_*mad 10

我将为这个问题提供一般的面向问答的答案:

回答问题

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

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

哪一个更好,SAX还是DOM?

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

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

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

基于树的API和基于事件的API之间有什么区别?

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

DOM Parser和SAX Parser有什么区别?

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

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

  • 无论客户端实际需要多少,DOM解析器始终为客户端应用程序提供整个文档.但是SAX解析器在任何给定时间始终仅为文档的各个部分提供客户端应用程序.

  • 使用DOM解析器,客户端应用程序中的方法调用必须是显式的,并形成一种链.但是使用SAX时,某些某些方法(通常由客户覆盖)将以某种特定事件发生时称为"回调"的方式自动(隐式)调用.这些方法不必由客户端显式调用,但我们可以明确地调用它们.

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

理想情况下,一个好的解析器应该快速(时间有效),节省空间,功能丰富且易于使用.但实际上,没有一个主解析器同时具有所有这些功能.例如,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树(即,将值设置为'grade'节点),然后保存整个修改过的树.如果他选择使用SAX解析器而不是DOM解析器,那么在这种情况下,他必须创建一个几乎与DOM树一样复杂的数据结构,然后才能完成工作.

一个例子

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

<?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> 
Run Code Online (Sandbox Code Playgroud)

用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);}

    }

}
Run Code Online (Sandbox Code Playgroud)

用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);
         }
   }


}
Run Code Online (Sandbox Code Playgroud)


Pre*_*raj 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>
Run Code Online (Sandbox Code Playgroud)
  • DOM将xml文档作为以下树结构存储在内存中.
  • DOM是W3C标准.
  • DOM解析器适用于文档对象模型.
  • DOM占用更多内存,是小型XML文档的首选
  • DOM易于向前或向后导航.

在此输入图像描述


  • SAX介绍了XML文档的基于事件一样start element:abc,end element:abc.
  • SAX不是W3C标准,它是由开发人员开发的.
  • SAX不使用内存,首选大型XML文档.
  • 向后导航是不可能的,因为它顺序处理文档.
  • 事件发生在节点/元素上,它给出了所有子节点(拉丁语nodus,'knot').

这个XML文档在通过SAX解析器传递时,将生成一系列事件,如下所示:

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
Run Code Online (Sandbox Code Playgroud)