我阅读了一些关于 XML 解析器的文章,并且遇到了 SAX 和 DOM 。
SAX 是基于事件的, DOM 是树模型 - 我不明白这些概念之间的差异。
根据我的理解,基于事件意味着节点会发生某种事件。就像当单击特定节点时,它将给出所有子节点,而不是同时加载所有节点。但是在 DOM 解析的情况下,它将加载所有节点并生成树模型。
我的理解是否正确?
请纠正我如果我错了或以更简单的方式向我解释基于事件和树模型。
答案 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 Parser功能丰富(因为它在内存中创建了一个DOM树,允许您重复访问文档的任何部分并允许您修改DOM树),但是当文档很大时,它的空间效率很低,学习如何使用它需要一点点时间。但是,SAX Parser在输入大文档时更节省空间(因为它不会创建内部结构)。而且,它比DOM Parser运行得更快,更容易学习,因为它的API非常简单。但从功能的角度来看,它提供的功能较少,这意味着用户自己必须处理更多,例如创建自己的数据结构。顺便问一下,什么是好的解析器?我认为答案实际上取决于您的应用程序的特征。
使用SAX解析器的实际应用是什么? 比使用DOM解析器更有利,反之亦然?什么是平常的 DOM解析器和SAX解析器的应用程序?
在以下情况下,使用SAX解析器比使用DOM解析器更有优势。
在以下情况下,使用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>
start element:abc
,end element:abc
。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:
逐节点解析
不将XML存储在内存中
我们无法插入或删除节点
自上而下遍历
DOM
在处理
占用更多内存
我们可以插入或删除节点
向任何方向移动。
如果我们需要找到一个节点而不需要插入或删除,我们可以使用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