DOM解析器

1.DOM标准

DOM(Document Object Model,文档对象模型)是W3C制定的一套规范标准,即规定了解析文件的接口。各种语言可以按照DOM规范去实现这些接口,给出解析文件的解析器。

各种基于DOM规范解析器必须按照DOM规范在内存中建立数据,DOM规范的核心是树模型。对于解析XML文件的解析器,解析器通过读入XML文件在内存中建立一个树,也就是说XML文件的标记、标记的文本内容、实体等都会和内存中树的某个节点相对应。一个应用程序可以方便地操作内存中树的节点来处理XML文档,获取自己所需要的数据。


2.DOM解析器

用 DOM 解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用 DOM 解析器的时候需要处理整个 XML 文档,所以对性能和内存的要求比较高,尤其是遇到很大的 XML 文件的时候。由于它的遍历能力,DOM 解析器常用于 XML 文档需要频繁的改变的服务中。W3C推荐使用DOM解析。



3.DOM和XML文件的互相转化

DOM解析器是DocumentBuilder类的实例。


XML转化为DOM对象

首先使用javax.xml.parsers包中的DocumentBuilderFactory类调用其类方法newInstance()实例化一个DocumentBuilderFactory对象:

[java] view plaincopyprint?
  1. DocumentBuilderFactory factory= DocumentBuilderFactory. newInstance();
DocumentBuilderFactory  factory= DocumentBuilderFactory. newInstance();

然后factory对象调用newDocumentBuilder()方法返回一个DocumentBuilder对象(称做DOM解析器),DocumentBuilder 类在javax.xml.parsers包中。例如:
[java] view plaincopyprint?
  1. DocumentBuilder builder=factory. newDocumentBuilder();
DocumentBuilder  builder=factory. newDocumentBuilder();

最后builder对象调用public Document parse(File f)方法解析参数f指定的文件,并将解析内容以对象的形式返回,该对象是实现了Document接口的一个实例,Document 接口在org.w3c.dom包中。例如:
[java] view plaincopyprint?
  1. Document document= builder. parse(new File("/mnt/sdcard/river.xml")) ;
Document  document= builder. parse(new File("/mnt/sdcard/river.xml")) ;

现在,应用程序只要分析内存中的树状结构数据Document,就可以获得XML文件中的各种数据了。


DOM解析器经常使用下述3个方法解析XML文件:


public Document parse(File f) throws SAXException, IOException

public Document parse(InputStream in) throws SAXException, IOException

public Document parse(String uri) throws SAXException, IOException


其中:

方法parse(File f)可以解析参数f指定的XML文件,例如:

[java] view plaincopyprint?
  1. File f= new File("/mnt/sdcard/river.xml");
  2. Document document= builder. parse(f) ;
File f= new File("/mnt/sdcard/river.xml");
Document  document= builder. parse(f) ;

直接这样指定assets下路径是不幸的。File file = new File(" file:///android_asset/river.xml");原因是assets下的资源为原生的,只能用流的方式读取,而且不能向assets目录下写。




方法parse(InputStream in)可以解析输入流参数in指向的XML文件,例如:

[java] view plaincopyprint?
  1. AssetManager assetManager = act.getAssets();
  2. InputStream inputStream = assetManager.open("price.xml"); ;
  3. Document document= builder. parse(inputStream) ;
AssetManager assetManager = act.getAssets();
InputStream inputStream  = assetManager.open("price.xml"); ;
Document  document= builder. parse(inputStream) ;


方法parse(String uri)可以解析参数uri指定的一个有效的资源,如果uri是一个链接地址,该链接地址必须是可以访问的,例如:

[java] view plaincopyprint?
  1. String uri="http://192.168.2.1/price.xml";
  2. Document document= builder. parse(uri) ;
String  uri="http://192.168.2.1/price.xml";
Document  document= builder. parse(uri) ;

除了通过parse方法得到Document对象外,还可以直接创建Document对象:

[java] view plaincopyprint?
  1. builder.newDocument();//可以创建一个Document,然后修改它
builder.newDocument();//可以创建一个Document,然后修改它

 
 

DOM对象转化为XML文件

解析器通过在内存中建立和XML结构相对应的树状结构数据,使得应用程序可以方便地获得XML文件中的数据,同时提供了使用内存中的树状结构数据建立一个XML文件的API,即使用解析器得到的Document对象建立一个新的XML文件。但是需要注意的是,Android2.1中没有相应的类包,从2.2开始才加入了。

解析器的parse方法将整个被解析的XML文件封装成一个Document节点返回,我们可以对Document节点进行修改,然后使用 Transformer对象将一个Document节点变换为一个XML文件。

步骤如下:

首先使用javax.xml.transform包中的TransformerFactory类建立一个对象,

[java] view plaincopyprint?
  1. TransformerFactory transFactory=TransformerFactory. newInstance()
TransformerFactory transFactory=TransformerFactory. newInstance()

然后transFactory对象调用newTransformer()方法得到一个Transformer对象,Transformer类在javax.xml.transform包中。

[java] view plaincopyprint?
  1. Transformer transformer=transFactory. newTransformer();
Transformer transformer=transFactory. newTransformer();

然后将被变换的Document对象封装到一个DOMSource对象中,DOMSource类在javax.xml.transform.dom包中。

[java] view plaincopyprint?
  1. DOMSource domSource=new DOMSource(document);
DOMSource  domSource=new DOMSource(document);

再然后将变换得到XML文件对象封装到一个StreamResult对象中,StreamResult类在javax.xml.transform.stream包中。
[java] view plaincopyprint?
  1. File file=new File("/mnt/sdcard/newXML.xml");//生成在SDCard下名为newXML的XML文件
  2. FileOutputStream out=new FileOutputStream(file);
  3. StreamResult xmlResult=new StreamResult(out);
File file=new File("/mnt/sdcard/newXML.xml");//生成在SDCard下名为newXML的XML文件
FileOutputStream out=new FileOutputStream(file);
StreamResult xmlResult=new StreamResult(out);

最后,Transformer 对象transformer 调用transform方法实施变换:
[java] view plaincopyprint?
  1. transformer.transform(domSource, xmlResult);
transformer.transform(domSource, xmlResult);


注意:以上用到了写文件创建文件等,所以需要在AndroidManifest.xml中加入访问SDCard的权限

<!--在SDCard中创建与删除文件权限 -->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!--往SDCard写入数据权限 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>



1. 节点(Node)

解析器调用parse方法返回一个实现了Document接口的实例,该实例也称做Document对象,应用程序可以从Document节点的子孙节点中获取整个XML文件中数据的细节,它是由实现了Node接口的实例组成的树状结构数据,这些实例称做Document对象中的节点。实际上Document接口也是Node接口的子接口,也就是说,parse方法将整个被解析的XML文件封装成一个节点返回(XML文件和内存中的Document节点相对应),因此,我们也可以称Document对象为Document节点。


Document对象中的节点形成树状结构,也就是说XML文件的标记、标记的文本内容、实体等都会和对象Document中的某个节点相对应。应用程序可以从Document节点的子孙节点中获取整个XML文件中数据的细节。


按照DOM规范,Node接口有如下的子接口:
Attr, CDATASection, CharacterData, Comment, Document, DocumentFragment, DocumentType, Element, Entity, EntityReference, Notation, ProcessingInstruction, Text

任何实现上述某个接口的类的实例都称做一个节点。



2.Node的常用方法


short getNodeType()
返回一个表示节点类型的常量(Node接口规定的常量值),例如,对于Element节点,getNodeType()方法返回的值为:Node.ELEMENT_NODE


NodeList getChildNodes()
返回一个由当前节点的所有子节点组成的NodeList对象。


Node getFirstChild()
返回当前节点的第一个子节点。


Node getLastChild()
返回当前节点的最后一个子节点。


NodeList getTextContent()
返回当前节点及所有子孙节点中的文本内容。



3.节点的子孙关系
为了解析规范的XML文件,DOM规范规定了各种类型节点之间可以形成的子孙关系,比如,Document节点有且仅有一个Element节点,也可以有一个DocumentType节点(规范的XML文件有且仅有一个根标记,也可以有一个与其关联的DTD文件),Element节点可以有Element子节点和Text子节点(规范的XML文件中的标记可以有子标记和文本)。

 

Document节点


Document节点的两个直接子节点的类型分别是DocumentType类型和Element类型,其中的DocumentType节点对应着XML文件所关联的DTD文件,通过进一步获取该节点子孙节点来分析DTDL文件中的数据;而其中的Element类型节点对应着XML文件的根节点,通过进一步获取该Element类型节点子孙节点来分析XML文件中的数据。


Document 节点经常使用下列方法获取和该节点相关的信息。


Element getDocumentElement()

返回当前节点的Element子节点。


DocumentType getDoctype()

返回当前节点的DocumentType子节点。


NodeList getElementsByTagName(String name)

返回一个NodeList对象,该对象由当前节点的Element类型子孙节点组成,这些子孙节点的名字由参数name指定。


NodeList getElementsByTagNameNS(String namespaceURI,String localName)

返回一个NodeList对象,该对象由当前节点的Element类型子孙节点组成, 这些子孙节点的名字由参数localName指定,名称空间由参数namespaceURI 指定。


String getXmlEncoding()

返回XML文件使用的编码,即XML声明中encoding属性的值。


boolean getXmlStandalone()

返回XML声明中的standalone属性的值。未指定时返回NULL

standalone 用来表示该文件是否呼叫其它外部的文件。 这里所指的外部文件其实就是查检XML是不是有效的约束文件,或是DTD或是Schema


String getXmlVersion()

返回XML声明中的version属性的值


其中getXmlEncoding getXmlVersion getXmlStandalong在Android2.1中是没有的。


要解析的XML文件:

[java] view plaincopyprint?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <rivers>
  3. <river name="灵渠" length="605">
  4. <introduction>
  5. 灵渠在广西壮族自治区兴安县境内,是世界上最古老的运河之一,有着“世界古代水利建筑明珠”的美誉。灵渠古称秦凿渠、零渠、陡河、兴安运河,于公元前214年凿成通航,距今已2217年,仍然发挥着功用。
  6. </introduction>
  7. <imageurl>
  8. http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
  9. </imageurl>
  10. </river>
  11. <river name="胶莱运河" length="200">
  12. <introduction>
  13. 胶莱运河南起黄海灵山海口,北抵渤海三山岛,流经现胶南、胶州、平度、高密、昌邑和莱州等,全长200公里,流域面积达5400平方公里,南北贯穿山东半岛,沟通黄渤两海。胶莱运河自平度姚家村东的分水岭南北分流。南流由麻湾口入胶州湾,为南胶莱河,长30公里。北流由海仓口入莱州湾,为北胶莱河,长100余公里。
  14. </introduction>
  15. <imageurl>
  16. http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
  17. </imageurl>
  18. </river>
  19. <river name="苏北灌溉总渠" length="168">
  20. <introduction>
  21. 位于淮河下游江苏省北部,西起洪泽湖边的高良涧,流经洪泽,青浦、淮安,阜宁、射阳,滨海等六县(区),东至扁担港口入海的大型人工河道。全长168km。
  22. </introduction>
  23. <imageurl>
  24. http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
  25. </imageurl>
  26. </river>
  27. </rivers>
<?xml version="1.0" encoding="utf-8"?>
<rivers>
<river name="灵渠" length="605">
<introduction>
灵渠在广西壮族自治区兴安县境内,是世界上最古老的运河之一,有着“世界古代水利建筑明珠”的美誉。灵渠古称秦凿渠、零渠、陡河、兴安运河,于公元前214年凿成通航,距今已2217年,仍然发挥着功用。
</introduction>
<imageurl>
http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
</imageurl>
</river>
<river name="胶莱运河" length="200">
<introduction>
胶莱运河南起黄海灵山海口,北抵渤海三山岛,流经现胶南、胶州、平度、高密、昌邑和莱州等,全长200公里,流域面积达5400平方公里,南北贯穿山东半岛,沟通黄渤两海。胶莱运河自平度姚家村东的分水岭南北分流。南流由麻湾口入胶州湾,为南胶莱河,长30公里。北流由海仓口入莱州湾,为北胶莱河,长100余公里。
</introduction>
<imageurl>
http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
</imageurl>
</river>
<river name="苏北灌溉总渠" length="168">
<introduction>
位于淮河下游江苏省北部,西起洪泽湖边的高良涧,流经洪泽,青浦、淮安,阜宁、射阳,滨海等六县(区),东至扁担港口入海的大型人工河道。全长168km。
</introduction>
<imageurl>
http://www.2cto.com/uploadfile/2012/0228/20120228094142711.jpg
</imageurl>
</river>
</rivers>


 

[java] view plaincopyprint?
  1. private Document parseXML(InputStream is)
  2. { if(is == null) return null;
  3. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  4. // dbf.setValidating(true);//设置检查XML文件的有效性
  5. // dbf.setIgnoringElementContentWhitespace(true);//设置忽略空白
  6. // dbf.setNamespaceAware(false);//设置为true时,由DocumentBuilderFactory产生的DOM解析器支持名称空间
  7. DocumentBuilder db = null; //DOM解析器
  8. Document doc = null;
  9. try {
  10. db = dbf.newDocumentBuilder();
  11. } catch (ParserConfigurationException e) {
  12. // TODO Auto-generated catch block
  13. e.printStackTrace();
  14. }
  15. try {
  16. doc = db.parse(is);//可以通过解析XML得到一个Document
  17. // db.newDocument();//可以创建一个Document,然后修改它
  18. } catch (SAXException e) {
  19. // TODO Auto-generated catch block
  20. e.printStackTrace();
  21. } catch (IOException e) {
  22. // TODO Auto-generated catch block
  23. e.printStackTrace();
  24. }
  25. DocumentType docType = doc.getDoctype();
  26. String xmlEncoding = doc.getXmlEncoding();//android2.1不支持
  27. String xmlVersion = doc.getXmlVersion();
  28. boolean isAlone = doc.getXmlStandalone();//android2.1不支持
  29. NodeList list = doc.getElementsByTagName("river");
  30. int length = list.getLength();
  31. for(int k = 0;k<length;k++)
  32. {
  33. Node node = list.item(k);
  34. String nodeName = node.getNodeName();
  35. String textContent = node.getTextContent();
  36. //取得当前节点下的所有Text节点内容,这里就包括introduction下和imageUrl下的Text以及空格
  37. }
  38. return doc;
    private Document  parseXML(InputStream is)
{   if(is == null) return null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//    	dbf.setValidating(true);//设置检查XML文件的有效性
//    	dbf.setIgnoringElementContentWhitespace(true);//设置忽略空白
//    	dbf.setNamespaceAware(false);//设置为true时,由DocumentBuilderFactory产生的DOM解析器支持名称空间
DocumentBuilder db = null; //DOM解析器
Document doc = null;
try {
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
doc = db.parse(is);//可以通过解析XML得到一个Document
//		     db.newDocument();//可以创建一个Document,然后修改它
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DocumentType docType =  doc.getDoctype();
String xmlEncoding = doc.getXmlEncoding();//android2.1不支持
String xmlVersion = doc.getXmlVersion();
boolean isAlone = doc.getXmlStandalone();//android2.1不支持
NodeList list = doc.getElementsByTagName("river");
int length = list.getLength();
for(int k = 0;k<length;k++)
{
Node node = list.item(k);
String nodeName = node.getNodeName();
String textContent = node.getTextContent();
//取得当前节点下的所有Text节点内容,这里就包括introduction下和imageUrl下的Text以及空格
}
return doc;


其中getXmlEncoding方法在XML设置了encoding的情况下,取不到,不知道为什么。

 

Element节点


Element节点是Document节点的最重要的子孙节点,因为被解析的XML文件的标记对应着这样类型的节点。表示Element节点的常量是Node.ELEMENT_NODE,一个节点用
short getNodeType()方法返回的值如果等于Node.ELEMENT_NODE,那么该节点就是Element节点。



Element节点经常使用下列方法获取和该节点相关的信息。


String getTagName()

返回该节点的名称,该名称就是此节点对应的XML中的标记名称。


String getAttribute(String name)

返回该节点中参数name指定的属性值,该属性值是此节点对应的XML标记中的属性值。


NodeList getElementsByTagName(String name)

返回一个NodeList对象,该对象由当前节点的Element类型子孙节点组成,这些子孙节点的名字由参数name指定。
NodeList getElementsByTagNameNS(String namespaceURI,String localName)返回一个NodeList对象,该对象由当前节点的Element类型子孙节点组成,这些子孙节点的 名字由参数localName指定,名称空间由参数namespaceURI 指定。


boolean hasAttribute(String name)

判断当前节点是否有名字是参数name指定的属性。


boolean hasAttributeNS(String namespaceURI, String localName)

判断当前节点是否有名字是参数name指定、名称空间是namespaceURI指定的属性。


String getTextContent() Android 2.1没有本API


getTagName和getNodeName的区别

getTagName()方法是Element接口中的方法,getNodeName()方法是Element接口从Node接口继承的方法。对于Element节点,getTagName()和getNodeName()返回的都是Element节点对应的XML文件中标记的名称。

 

Text节点


规范的XML文件的非空标记可以有子标记和文本内容。在DOM规范中,解析器使用Element节点封装标记,用Text节点封装标记的文本内容,即Element节点可以有Element子节点和Text节点。例如,对于下列标记:

[java] view plaincopyprint?
  1. <姓名>张小三
  2. <性别>男</性别>
  3. <年龄>23</年龄>
  4. </姓名>
<姓名>张小三
<性别>男</性别>
<年龄>23</年龄>
</姓名>


该标记对应的Element节点共有7个子孙节点,其中2个Element子节点、3个Text子节点和2个Text孙节点。这些节点和XML中的标记及文本有如下的对应关系。
2个Element子节点分别对应“姓名”标记的2个子标记:“性别”和“年龄”。3个Text子节点分别对应着:“<姓名>”与“<性别>”之间的文本、“</性 别>”与“<年龄>”之间的空白类字符、“</年龄”与“</姓名>”之间的空白类字符。两个Text孙节点分别对应标记“性别”和“年龄”的文本内容。


表示Text节点的常量是Node.TEXT_NODE,一个节点调用short getNodeType()方法返回的值如果等于Node.TEXT_NODE,那么该节点就是Text节点。
Text节点使用String getWholeText()方法获取节点中的文本(包括其中的空白字符)。Android2.1中没有本API


注意:对于Text节点,getNodeName()方法返回的是“#text”。


对于应用程序而言,Text节点是较重要的节点,因为Text节点封装着XML标记中的文本数据。


Attr节点

在XML文件中,属性并不是标记的子标记,因此,在DOM规范中,Att节点也不是Element节点的子节点。


如果想解析XML文件中标记的属性,必须让对应的Element节点调用NamedNodeMap getAttributes()方法。该方法返回的NamedNodeMap对象由节点组成,这些节点可以被转换为Attr节点。Attr节点通过调用String getName()方法返回属性的名字,调用String getValue()方法返回属性的值。



处理空白

标记之间的缩进区域是为了使得XML文件看起来更美观而形成的,但解析器并不知道这一点,所以解析器仍然认为它们是有用的文本数据(由空白类字符组成)

人们习惯上称标记之间的缩进区是可忽略空白,这实际上不是很准确,因为XML文件的标记可以有文本和子标记(混合内容),在这种情况下,标记之间的区域中就可能包含非空白的字符内容。
如果我们不允许标记有混合内容,即标记要么只有子标记要么只有文本,在这种情形下,称标记之间的缩进区域是可忽略空白就比较恰当,这些空白区确实使得XML文件看起来更加美观,也是它们存在的惟一目的。


如果想让DOM解析器忽略缩进空白,即这些缩进空白不在Document中形成Text节点,那么XML文件必须是有效的,而且所关联的DTD文件必须规定XML文件的标记不能有混合内容,同时DocumentBuilderFactory对象在给出DOM解析器之前,必须调用setIgnoringElementContentWhitespace(boolean whitespace)进行设置,将参数whitespace的值设为true。


验证规范性和有效性

通过DocumentBuilderFactory对象factory事先设置是否检查XML文件的有效性,如:factory.setValidating(true);

 

DocumentType节点


DocumentType节点是Document节点的一个子节点。我们已经知道,解析器的parse方法将整个被解析的XML文件封装成一个Document节点返回,Document节点的两个子节点的类型分别是DocumentType类型和Element类型,其中的DocumentType节点对应着XML文件所关联的DTD文件,通过进一步获取该节点子孙节点来分析DTD文件中的数据。Document节点调用getDoctype() 返回当前节点的DocumentType子节点。


获取DTD的基本信息


假如XML文件中的DOCTYPE声明为:<!DOCTYPE 房子 PUBLIC "-//ISO88//beijing//ForXML/Ch" "b1.dtd",那么

DocumentType节点调用getName()方法返回的是:房子
调用getPublicId()方法返回的是:-//ISO88//beijing//ForXML/Ch
调用getSystemId()方法返回的是:b1.dtd


一个XML文件可以关联一个外部DTD或一个内部DTD,也可二者皆有(见第3.9节)。如果XML关联一个内部DTD,DocumentType节点调用getInternalSubset()方法可以返回内部DTD的内容。


获取实体


DTD文件中可以定义实体,然后与该DTD文件关联的XML文件可以通过实体引用使用该实体。实体又分为内部实体和外部实体,所谓内部实体就是实体的内容已经包含在DTD文件本身中;而外部实体是指实体的内容是DTD文件以外的其他文件。
解析器将实体封装为Entity节点,DocumentType节点调用
NamedNodeMap getEntities()
方法可以得到全部的实体,该方法返回的NamedNodeMap对象由节点组成,这些节点可以被转换为Entity节点。Entity节点通过调用getTextContent()方法返回实体,如果实体是一个外部文件,Entity节点通过调用getInputEncoding()方法可以返回解析该实体所使用的编码;如果是内部实体,getInputEncoding()方法返回null。


CDATASection节点


在XML文件中,标记内容中的文本数据不可以含有左尖括号、右尖括号、与符号、单引号和双引号这些特殊字符,如果想使用这些字符,办法之一是通过实体引用,如果需要许多这样的字符,文本数据中就会出现很多实体引用或字符引用,导致文本数据的阅读变得困难。使用CDATA(Character Data)段可以解决这一问题,CDATA段用“<![CDATA[”作为段的开始,用“]]>”作为段的结束,段开始和段结束之间称为CDATA段的内容,解析器不对CDATA段的内容做分析处理,因此,CDATA段中的内容可以包含任意的字符。
在DOM规范中,解析器使用CDATASection节点封装CDATA段,CDATASection节点可以是Element的节点的子节点。


节点数目的计算办法如下。


首先将标记中交替出现的普通文本和CDATA段按照它们在标记中出现的先后顺序排列,如:
普通文本1 CDATA段1 普通文本2 CDATA段2 普通文本3


那么该标记对应的Element节点的子节点顺序如下。


1 / Text节点:从“普通文本1”到“普通文本3”的区域,节点的文本内容是普通文本和CDATA段中的内容。
2 / CDATASection节点:从“CDATA段1”到“普通文本3”的区域,节点的文本内容是普通文本和CDATA段中的内容。
3 / Text节点:从“普通文本2”到“普通文本3”的区域,节点的文本内容是普通文本和CDATA段中的内容。
4 / CDATASection节点:从“CDATA段2”到“普通文本3”的区域,节点的文本内容是普通文本和CDATA段中的内容。
5 / Text节点:“普通文本3”,节点的文本内容是普通文本。



表示CDATASection节点的常量是Node.CDATA_SECTION_NODE,一个节点调用short getNodeType()方法返回的值如果等于Node.CDATA_SECTION_NODE,那么该节点就是CDATASection节点。CDATASection节点使用String getWholeText()方法获取节点中的文本,即CDATA段中的文本(包括其中的空白字符)。


注意:对于CDATASection节点,getNodeName()方法返回的是“#cdata-section”。

更多 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353129.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

批量打印pdf并合并_批量打印CAD图(无删减版)

前面两期小编出的PDF教程想必用了的人都觉得还不错吧&#xff1f;(此处应有掌声)上一期提到的CAD批量打印今天放出来了&#xff0c;擦亮眼睛往下看很多时候大批量的一堆图纸要输出&#xff0c;比如下面这个当然这批图纸并不多&#xff0c;也只是局部的&#xff0c;通常一个项目…

expect详解及自动登录脚本的实现

expect可以让一些交互的任务自动完成&#xff0c;我们可以将一些交互过程写入脚本&#xff0c;ssh登录就是一个简单的实现&#xff0c;下面将介绍expect的用法。 1 安装 yum install -y expect 2 语法介绍 expect - send 这两个指令会配合使用&#xff0c;当expect接收到一个和…

极端懒惰:使用Spring Boot开发JAX-RS服务

我认为可以公平地说&#xff0c;作为软件开发人员&#xff0c;我们一直在寻找编写较少代码的方法&#xff0c;这些方法可以自动完成或不能自动完成更多工作。 考虑到这一点&#xff0c;作为Spring产品组合的骄傲成员的Spring Boot项目破坏了传统方法&#xff0c;极大地加快了并…

透明怎么弄_最新版微信如何设置透明背景?这样设置,效果令人惊喜

微信叒更新了&#xff0c;你的微信有更新吗&#xff1f;听说这次更新是安卓端的先更新&#xff0c;苹果端的还不能更新。今天小编要跟大家分享的是新版微信应该如何设置透明背景&#xff0c;不清楚微信透明背景长什么样子的&#xff1f;没关系&#xff0c;给你看看设置透明背景…

QueryRunner使用

在相继学习了JDBC和数据库操作之后&#xff0c;我们明显感到编写JDBC代码并非一件轻松的事儿。为了帮助我们更高效的学习工作&#xff0c;从JDBC的繁重代码中解脱出来&#xff0c;老佟给我们详尽介绍了一个简化JDBC操作的组件——DBUtils。我们今天主要学习了它所提供的两个类和…

基于vue的UI框架集锦(移动端+pc端)

1. vonic 一个基于 vue.js 和 ionic 样式的 UI 框架&#xff0c;用于快速构建移动端单页应用&#xff0c;很简约&#xff0c;是我喜欢的风格 star 2.3k 中文文档 在线预览 2.vux 基于WeUI和Vue(2.x)开发的移动端UI组件库 star 10k 基于webpackvue-loadervux可以快速开发移动端页…

com技术内幕 代码_CFan科学院:零门槛极速抠图技术探秘

将照片中的人或物从背景中分离出来&#xff0c;俗称抠图。要实现完美的抠图&#xff0c;没有一定的PS(Photoshop)基础是根本无法实现的&#xff0c;不过现在有个名为Remove.bg的网站&#xff0c;号称5秒钟就可以完成复杂的抠图&#xff0c;彻底将抠图难度降到了零门槛&#xff…

关于级联删除和级联修改

曾经因为级联删除的问题浪费了N多时间&#xff0c;顾此在这里写下小小心得&#xff0c;供大家借鉴。在数据库分别建立表t_food&#xff08;菜单&#xff09;和表t_book(订单)&#xff0c;如下所示&#xff1a;t_food:————————————————————————————…

python:数据库连接操作入门

模块 1 import pymssql,pyodbc 模块说明 pymssql和pyodbc模块都是常用的用于SQL Server、MySQL等数据库的连接及操作的模块&#xff0c;当然一些其他的模块也可以进行相应的操作&#xff0c;类似adodbapi、mssql、mxODBC等&#xff0c;我们在实际用的时候选择其中一个模块就好&…

java面试题:集合_Java:选择正确的集合

java面试题:集合这是在您的应用程序中选择Set &#xff0c; List或Map的正确实现的快速指南。 最好的通用或“主要”实现可能是ArrayList&#xff0c;LinkedHashMap和LinkedHashSet。 它们的整体性能更好&#xff0c;除非您需要其他实现提供的特殊功能&#xff0c;否则应使用它…

c:forEach

简介 <c:forEach>为循环控制&#xff0c;它可以将集合(Collection)中的成员循序浏览一遍。运作方式为当条件符合时&#xff0c;就会持续重复执行<c:forEach>的本体内容。 语法 语法1&#xff1a;迭代一集合对象之所有成员 <c:forEach [var"varName"] …

b500k带开关电位器内部构造_R138带开关大功率大电流电位器 B10K B500K

全阻值 :500Ω-1MΩ全阻值公差:20%阻抗特性型式:A,B,C,D杂音:Less than 100mV at 20 mmc.绝缘阻抗:More than 10MΩat DC 250V耐电压:1 minute at AC 250V残留阻值:Term.1~2:Less than 10Ω Term.2~3:Less than 10Ω同步误差(双联):-40dB~0dB3dB额定电压B线性:10mm,15mm:AC 100…

Java 8:将匿名类转换为Lambda表达式

将匿名类&#xff08;实现一种方法&#xff09;重构为lambda表达式&#xff0c;可使您的代码更简洁明了。 例如&#xff0c;这是Runnable及其lambda等效项的匿名类&#xff1a; // using an anonymous class Runnable r new Runnable() {Overridepublic void run() {System.o…

如何去掉a标签的下划线

首先来了解下<a>标签的一些样式&#xff1a; <a>标签的伪类样式 一组专门的预定义的类称为伪类&#xff0c;主要用来处理超链接的状态。超链接文字的状态可以通过伪类选择符&#xff0b;样式规则来控制。伪类选择符包括&#xff1a; 总: a 表示所有状态下的连接 …

Android.os.SystemClock

https://www.linuxidc.com/Linux/2011-11/48325p2.htm 文档中对System.currentTimeMillis()进行了相应的描述&#xff0c;就是说它不适合用在需要时间间隔的地方&#xff0c;如Thread.sleep, Object.wait等&#xff0c;因为可以通过System.setCurrentTimeMillis来改变它的值。要…

批量修改数据_#泰Q头条#065期 四步搞定Excel表中的批量数据修改

『闻道有先后 术业有专攻』又到每周五我们Offcie小课堂时间&#xff0c;每周学一点儿&#xff0c;知识从未如此简单&#xff0c;也真诚的希望各位能在留言板写下你们宝贵的建议&#xff0c;给您带来更具价值的分享。这期跟大家带来的Excel表数据整理功能——统一数值变动的实用…

列表与for循环

列表(list)&#xff1a; python基础数据类型之一&#xff1a;其他语言中也有列表的概念。可索引&#xff0c;可切片&#xff0c;可加长。 列表可以储存大量数据。 #作用&#xff1a;多个装备&#xff0c;多个爱好&#xff0c;多门课程&#xff0c;多个女朋友等#定义&#xff1a…

html用a标签怎么提交表单?

html用a标签怎么提交表单&#xff1f; 2011-03-08 10:55MeACrazy | 分类&#xff1a;Html/Css |浏览10003次如下代码请 帮忙完善 function judgeDelete(){if(confirm("确定要删除吗&#xff1f;")){window.location.href"doDelete.jsp";}}<form action&…

python 读取geotiff_科学网—利用python GDAL库读写geotiff格式的遥感影像方法 - 张伟的博文...

(1)利用python GDAL库读写geotiff格式的遥感影像方法&#xff0c;具有很好的参考价值&#xff0c;不错&#xff01;from osgeo import gdalimport numpy as npdef read_tiff(inpath):dsgdal.Open(inpath)rowds.RasterXSizecolds.RasterYSizebandds.RasterCountgeoTransformds.G…

滑动拼图验证码操作步骤:_拼图项目:延期的后果

滑动拼图验证码操作步骤&#xff1a;Mark Reinhold先生于2012年7月宣布 &#xff0c;他们计划从Java 8撤消Jigsaw项目 &#xff0c;因为Jigsaw计划于2013年9月&#xff08;从现在开始一年&#xff09;推迟其发布。 这个日期是众所周知的&#xff0c;因为Oracle已决定实施Java的…