三、XML
3.1 XML 概述
- HTML 和XML 同宗同源,但是两者之间存在着重要的区别
- 与HTML 不同, XML 是大小写敏感的。例如,
<H1>
和<hl>
是不同的XML 标签。 - 在HTML 中,如果从上下文中可以分清哪里是段落或列表项的结尾,那么结束标签(如
</p>
或</li>
) 就可以省略,而在XML 中结束标签绝对不能省略。 - 在XML 中,只有单个标签而没有相对应的结束标签的元素必须以/ 结尾,比如
<imgsrc="coffeecup.png” />
。这样,解析器就知道不需要查找</img>
标签了。 - 在XML 中,属性值必须用引号括起来。在HTML 中,引号是可有可无的。例如,
<applet code="MyApplet.class" width=300 height=300>
对HTML 来说是合法的,但是对XML 来说则是不合法的。在XML 中,必须使用引号, 比如, width=“300” 。 - 在HTML 中,属性名可以没有值。例如,< input type=“radio” name=“language” value=“Java” checked>` 。在XML 中,所有属性必须都有属性值。比如, checked=“true” 或checked="checked” 。
- 与HTML 不同, XML 是大小写敏感的。例如,
-
XML 文档的结构
-
XML 文档应当以一个文档头开始,文档头是可选的,但是强烈推荐你使用文档
< ?xml version="1.0"?> // 或 < ?xml version="1.0" encoding="UTF-8"?>
-
文档头之后通常是文档类型定义,文档类型定义是确保文档正确的一个重要机制,但是它不是必需的。
< ! DOffiPE web-app PUBLIC "-//Sun Microsystems, Inc. //DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
-
XML 文档的正文包含根元素,根元素包含其他元素。
< ?xml version="1.0"?> <!DOCTYPE configuration ... > <configuration> <title> <font> <name>Helvetica</name> <size>36</size> </font> </title> ... </configuration>
在设计XML 文档结构时,最好让元素要么包含子元素,要么包含文本,应该避免下面的情况:
<font> Helvetica <size>36</size> </font>
XML 元素可以包含属性,但是属性的灵活性要差很多。属性只应该用来修改值的解释,而不是用来指定值。如果你发现自己陷入了争论,在纠结千某个设置是否是对某个值的解释所作的修改,那么你就应该对属性说“不",转而使用元素,许多有用的文档根本就不使用属性。
-
其他一些标记
-
字符引用(character reference) 的形式是&#十进制值;或&#x 十六进制值;。
éé
-
实体引用(entity reference) 的形式是&name, 。
< > & " ' <!-- 小千、大千、& 、引号、省略号 -->
-
CDATA 部分(CDATA Section) 用来限定其界限。
<![CDATA[<&> are my favorite delimiters]]> <!-- 注意: CDATA 部分不能包含字符串"]]>" -->
-
处理指令(processing instruction) 是那些专门在处理XML 文档的应用程序中使用的指令,它们由<? 和?>来限定其界限。
< ?xm1-stylesheet href="mystyle.css" type="text/css"?>
-
注释(comment) 用<!– 和 –>限定其界限。
-
-
3.2 解析XML 文档
-
两种XML 解析器
- 像文档对象模型( Document Object Model, DOM ) 解析器这样的树型解析器( tree parser) ,它们将读入的XML 文档转换成树结构。
- 像XML 简单API (Simple API for XML, SAX) 解析器这样的流机制解析器(streaming parser ) ,它们在读入XML 文档时生成相应的事件
-
使用步骤
-
从DocumentBuilderFactory 中创建DocumentBuilder 对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance() ; DocumentBuilder builder = factory.newDocumentBuilder();
-
从文件中读入某个文档
// 用 file File f = ... Document doc = builder.parse(f); // 用一个URL URL u = ... Document doc = builder.parse(u); // 指定一个任意的输入流 InputStream in = ... Document doc = builder.parse(in);
-
-
Document 对象是XML 文档的树型结构在内存中的表示方式,它由实现了Node 接口及其各种子接口的类的对象构成。
-
通过调用getDocumentElement 方法来启动对文档内容的分析,它将返回根元素。getTagName 方法可以返回元素的标签名。getChildNodes方法获得该元素的子元素,返回一个类型为Nodelist 的集合。Nodelist 类型中,item 方法将得到指定索引值的项,getLength 方法则提供了项的总数。
Element root = doc.getDocumentElement(); // root元素的标签名 root.getTagName() // 获取 root 的子标签 Nodelist children = root.getChildNodes() // 遍历所有子标签 for (int i = 0; i < children.getLength(); i++) { Node child = children.itern(i); ... }
-
分析子元素时要很仔细。如处理以下文档
<font> <name>Helvetica</name> <size>36</size> </font>
你预期font 有两个子元素,但是解析器却报告说有5 个:
-
和
之间的空白字符 -
name 元素
-
和
之间的空白字符 -
size 元素
-
和 之间的空白字符
DOM树如下
-
-
若只需要子元素,则使用以下代码,这只会得到两个元素,它们的标签名是name 和size 。用getFirstChild 方法获取第一个元素,用getData 方法获取存
储在Text 节点中的字符串。用getlastChild 方法得到最后一项子元素,用getNextSibling 得到下一个兄弟节点。for (int i = 0; i < children.getLength(); i++) { Node child = children.itern(i); if (child instanceof Element){ Element childElement = (Element) child; // 获取它们包含的文本字符串 Text textNode = (Text) childElement.getFirstChild(); String text = textNode.getData().trim(); ... } }
-
枚举节点的属性,可以调用getAttributes 方法。它返回一个NamedNodeMap 对象,其中包含了描述属性的Node 对象。可以用和遍历Nodelist 一样的方式在NamedNodeMap中遍历各子节点。然后,调用getNodeName 和getNodeValue 方法可以得到属性名和属性值。
NamedNodeMap attributes = element.getAttributes() ; for (int i= 0; i < attributes.getlength(); i++) Node attribute = attributes.item(i); String name = attribute.getNodeName(); String value = attribute.getNodeValue(); ... } // 如果知道属性名, 则可以直接获取相应的属性值: String unit = element.getAttribute("unit");
-
DOMTreeModel类实现了TreeModel 接口。getRoot 方法会返回文档的根元素, getChild 方法可以得到子元素的节点列表, 返回被请求的索引值对应的项。表的单元格渲染器显示了以下内容
- 对元素,显示的是元素标签名和由所有的属性构成的一张表。
- 对字符数据,显示的是接口( Text 、Comment 、CDATASection ) ,后面跟着数据,其中换行和回车字符被 \n 和 \r 取代。
- 对其他所有的节点类型,显示的是类名,后面跟着toString 的结果。
-
3.3 验证XML 文档
-
指定文档结构,可以提供一个文档类型定义(DTD) 或一个XML Schema 定义。
<!-- DTD规则:一个font 元素必须总是有两个子元素,分别是name 和size 。 --> <!ELEMENT font (name, size)> <!-- 相同的Schema规则,但可以表达更加复杂的验证条件 --> <xsd:element name="font"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="size" type="xsd:int"/> </xsd:sequence> </xsd:element>
-
文档类型定义
-
提供DTD 的方式有多种。
-
直接将其纳入到XML 文档中的DOCTYPE 声明中,位千由[ … ]限定界限的块中。文档类型必须匹配根元素的名字
< ?xml version="1.0"?> <!DOCTYPE configuration [ <!ELEMENT configuration... > more rules ... ]> <configuration> ... </configuration>
-
把DTD 存储在外部会更具意义, SYSTEM 声明可以用来实现这个目标。指定一个包含DTD 的URL。
<!DOCTYPE configuration SYSTEM "config.dtd"> <!-- 或者 --> <!DOCTYPE configuration SYSTEM "http://myserver.com/config.dtd">
-
如果你使用的是DTD 的相对URL ( 比如“config . dtd” ) ,那么要给解析器一个File 或URL 对象,而不是InputStream 。如果必须从一个输入流来解析,那么请提供一个实体解析器
-
如果你使用的是DOM 解析器,并且想要支持PUBLIC 标识符,请调用DocumentBuilder 类的setEntityResolver 方法来安装EntityResolver 接口的某个实现类的一个对象。该接口只有一个方法: resolveEntity 。下面是一个典型实现的代码框架:
class MyEntityResolver implements EntityResolver { @Override public InputSource resolveEntity(String publicID, String systemID) { if (publicID.equals(a known ID)) { return new InputSource(DTD data); } else { return null; // use default behavior } } } // 你可以从InputStream 、Reader 或宇符串中构建轮入源。
-
-
-
ELEMENT 规则
<!-- menu 元素包含0 或多个item 元素 --> <!ELEMENT menu (item)*> <!-- font 是用一个name 后跟一个size 来描述的 --> <!ELEMENT font (name, size)> <!-- name 和 size 都包含文本 --> <!ELEMENT name (#PCDATA) > <!ELEMENT size (#PCDATA) >
-
元素可以包含文本只有两种合法的情况
-
该元素只包含文本
<!ELEMENT name (#PCDATA)>
-
该元素包含任意顺序的文本和标签的组合
<!ELEMENT para (#PCDATA|em|strong|code)*>
-
其他任何类型的包含#PCDATA 的规则都是不合法的。
<!ELEMENT captionedImage (image, #PCDATA)>
-
在设计DTD 时,让其中所有的元素要么包含其他元素,要么只有文本
-
在DTD 规则中并不能为元素指定任意的正则表达式, XML 解析器会拒绝某些导致非确定性的复杂规则,因为XML 标准允许解析器假设DTD 都是非二义性的。
-
-
-
指定描述合法的元素属性的规则
<!ATTLIST element attribute type default>
- 合法的属性类型(type)
-
CDATA 属性值的处理与你前面看到的对# PCDATA 的处理有着微妙的差别,并且与<![CDATA[…]> 部分没有多大关系。属性值首先被规范化,也就是说,解析器要先处理对字符和实体的引用(比如&#233 ; 或& lt; ),并且要用空格来替换空白字符。
-
NMTOKEN (即名字标记)与CDATA 相似, 但是大多数非字母数字字符和内部的空白字符是不允许使用的,而且解析器会删除起始和结尾的空白字符。NMTOKENS 是一个以空白字符分隔的名字标记列表。
-
ID 结构是很有用的, ID 是在文档中必须唯一的名字标记,解析器会检查其唯一性。IDREF 是对同一文档中已存在的ID 的引用,解析器也会对它进行检查。IDREFS 是以空白字符分隔的ID 引用的列表。
-
ENTITY 属性值将引用一个“未解析的外部实体” 。这是从SGML 那里沿用下来的,在实际应用中很少见到。DTD 也可以定义实体,或者定义解析过程中被替换的缩写。
<!-- 实体定义 --> <!ENTITY back.label "Back"> <!-- 引用实体,解析器会用替代字符串来替换该实体引用。 --> <menuitem label="&back.label;"/>
-
属性默认值( default )
- 例子
<!-- 描述了font 元素的style 属性,它有4 个合法的属性值,默认值是 plain --> <!ATTLIST font style (plain|bold|italic|bold-italic) "plain"> <!-- size 元素的unit 属性可以包含任意的字符数据序列 --> <!ATTLIST size unit CDATA #IMPLIED>
-
置你的解析器,解析DTD
factory.setValidating(true);
- 该工厂生成的所有文档生成器都将根据DTD 来验证它们的输入。验证的最大好处是可以忽略元素内容中的空白字符。
<font> <name>Helvetica</name> <size>36</size> </font>
- 一个不进行验证的解析器会报告font 、name 和size 元素之间的空白字符,但检查时会知道它们之间的空白字符不是文,就调用
factory.setlgnoringElementContentWhitespace(true);
这样生成器将不会报告文本节点中的空白字符。
-
只要使用验证,就应该安装一个错误处理器,这需要提供一个实现了ErrorHandler 接口的对象。可以通过DocumentBuilder 类的setErrorHandler 方法来安装错误处理器
builder.setErrorHandler(handler);
-
-
XML Schema
-
在文档中引用Schema 文件,用前缀xsd: 来表示XSL Schema 定义的命名空间。
< ?xml version="1.0"?> <configuration xmIns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemalocati on="config.xsd"> </configuration> <!-- Schema文件config.xsd 会被用来验证该文档。 -->
-
Schema 为每个元素都定义了类型。类型可以是简单类型, 即有格式限制的字符串,或者是复杂类型。简单类型已内置,如下
xsd:string xsd:int xsd:boolean <!-- 枚举类型 StyleType --> <xsd:simpleType name="StyleType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="PLAIN"/> <xsd:enumeration value="BOLD"/> <xsd:enumeration value="ITALIC"/> <xsd:enumeration value="BOLD_ITALIC"/> </xsd:restriction> </xsd:simpleType>
-
定义元素时,要指定它的类型,类型约束了元素的内容。
<xsd:element name="name" type="xsd:string"/> <xsd:element name="size" type="xsd:int"/> <!-- 例 --> <size> 10</size> <xsd:element name="style" type="StyleType"/> <!-- 例 --> <style>PLAIN</style>
-
类型组合成复杂类型,FontType 是name 、size 和style 元素的序列,使用了ref属性来引用在Schema 中位千别处的定义。
<xsd:complexType name="FontType"> <xsd:sequence> <xsd:element ref="name"/> <xsd:element ref="size"/> <xsd:element ref="style"/> </xsd:sequence> </xsd:complexType>
-
可以嵌套定义,xsd:sequence 结构和DTD 中的连接符号等价,而 xsd:choice 结构和I 操作符等价
<xsd:complexType name="contactinfo"> <xsd:choice> <xsd:element ref="email"/> <Xsd:element ref="phone"/> </xsd:choice> </xsd:complexType> <!-- 等价DTD "email|phone" -->
-
使用minoccurs 和maxoccurs 属允许重复元素
<xsd:element name="item" type="..." minoccurs="0" maxoccurs="unbounded"> <!-- 等价DTD "item*" -->
-
使用 xsd:attribute 指定属性
<xsd:element name="size"> <xsd:complexType> ... <xsd:attribute name="unit" type="xsd:string" use="optional" default="cm"/> </xsd:complexType> </xsd:element> <!-- 等价DTD "<!ATTLIST size unit CDATA #IMPLIED "cm">" -->
-
把Schema 的元素和类型定义封装在xsd:schema 元素中
<xsd:schema xmIns:xsd="http://www.w3.org/2001/XMLSchema"> ... </xsd:schema>
-
解析带有Schema 的XML 文件,类似DTD但有不同
-
必须打开对命名空间的支持,即使在XML 文件里你可能不会用到它。
factory.setNamespaceAware(true);
-
准备好处理Schema 的工厂
final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; final String W3_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; factory.setAttribute (JAXP_SCHEMA_LANGUAGE , W3_XML_SCHEMA);
-
解析器不会丢弃元素中的空白字符
-
-
-
实用示例(P142)swing实例
3.4 使用XPath 来定位信患
-
XPath 语言使得访问树节点变得很容易。以下示例可以通过通过对XPath 表达式
/configuration/database/username
求值来得到database
中的username 的值<configuration> ... <database> <username>dbuser</username> <password>secret</password> ... </database> </configuration>
-
使用Xpath 执行下列操作比普通的DOM 方式要简单得多
- 获得文档节点。
- 枚举它的子元素。
- 定位database 元素。
- 定位其子节点中名字为username 的节点。
- 定位其子节点中的text 节点。
- 获取其数据。
-
XPath 可以描述XML 文档中的一个节点集,如
/gridbag/row
,描述了根元素gridbag 的子元素中所有的row 元;使用[] 操作符来选择特定元素,如/gridbag/row[1]
这表示的是第一行;使用@ 操作符可以得到属性值,如/gridbag/row[1]/cell[1]/@anchor
描述了第一行第一个单元格的anchor 属性;/gridbag/row/cell/@anchor
描述了作为根元素gridbag 的子元素的那些row 元素中的所有单元格的anchor 属性节点。 -
XPath 有很多有用的函数,如
count(/gridbag/row
返回gridbag 根元素的row 子元素的数量。 -
计算XPath 表达式
// 从XPathFactory 创建一个XPath 对象 XPathFactory xpfactory = XPathFactory.newInstance(); path = xpfactory.newXPath(); // 调用evaluate 方法来计算XPath 表达式,返回节点文本 String username = path.evaluate("/configuration/database/username", doc) ; // 结果是多个节点 NodeList nodes = (NodeList) path.evaluate("/gridbag/row", doc, XPathConstants.NODESET); // 结果只有一个节点 Node node = (Node) path.evaluate("/gridbag/row[1]", doc, XPathConstants.NODE); // 结果是一个数字 Number count = (Number) path.evaluate("count(/gridbag/row)", doc, XPathConstants.NUMBER); // 不必从文档的根节点开始搜索,可以从任意一个节点或节点列表开始。如果你有前一次计算得到的节点,那么就可以调用: result = path.evaluate(expression, node);
3.5 使用命名空间
-
XML 的命名空间可以用千元素名和属性名。名字空间是由统一资源标识符( Uniform Resource Identifier, URI ) 来标识,HTTP 的URL 格式是最常见的标识符。注意, URL 只用作标识符字符串,而不是一个文件的定位符。在命名空间的URL 所表示的位置上不需要有任何文档, XML 解析器不会尝试去该处查
找任何东西。http://www.w3.org/2001/XMLSchema uuid:lc759aed-b748-475c-ab68-10679700c4f2 urn:com:books-r-us // 以下两个名字空间标识符,表示了不同的命名空间,尽管Web 服务器将为这两个URL 提供同一个文档。 http://www.horstmann.com/corejava http://www.horstmann.com/corejava/index.html
-
有子元素继承了它们父元素的命名空间,而不带显式前缀的属性并不是命名空间的一部分。
<configuration xmIns="http://www.horstmann.com/corejava" xmIns:si ="http://www.bipm.fr/enus/3_ SI/si.html"> <size value= "210" si:unit="mm"/> ... </configuration>
元素configuration 和size 是URI 为 http://www.horstmann.com/orejava 的命名空间的一部分。属性si: unit 是URI 为 http://www.bipm.fr/enus/3SI/si.html 的命名空间的一部分。然而,属性value 不是任何命名空间的一部分。
-
打开命名空间处理特性,调用DocumentBuilderFactory 类的setNamespaceAware 方法设置后,该工厂产生的所有生成器便都支持命名空间。
factory.setNamespaceAware(true);
节点有三个属性:
- 带有前缀的限定名(qualified) ,由getNodeName 和getTagName 等方法返回。
- 命名空间URI , 由getNamespaceURI 方法返回。
- 不带前缀和命名空间的本地名( local name ) ,由getLocalName 方法返回。
-
例
<xsd:schema xmIns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- 限定名 = xsd:schema --> <!-- 命名空间URI = http://www. w3. org/2001/XMLSchema --> <!-- 本地名 = schema -->
3.6 流机制解析器
- DOM 解析器会完整地读入XML 文档,然后将其转换成一个树形的数据结构。但是,如果文档很大,并且处理算法又非常简单,可以在运行时解析节点, 而不必看到完整的树形结构,那么DOM 可能就会显得效率低下了。使用流机制解析器。
-
使用SAX 解析器
-
SAX 解析器在解析XML 输入数据的各个组成部分时会报告事件,但不会以任何方式存储文档,而是由事件处理器建立相应的数据结构。
DOM 解析器是在SAX 解析器的基础上构建的,它在接收到解析器事件时构建DOM 树。
-
在使用SAX 解析器时,需要一个处理器来为各种解析器事件定义事件动作。ContentHandler 接口定义了若干个在解析文档时解析器会调用的回调方法。
- startElement 和endElement 在每当遇到起始或终止标签时调用。
- characters 在每当遇到字符数据时调用。
- startDocument 和endDocument 分别在文档开始和结束时各调用一次。
-
例子
<font> <name>Helvetica</name> <size units="pt">36</size> </font> // 解析器产生的回调 // startElement, 元素名: font // startElement, 元素名: name // characters, 内容: Helvetica // endElement, 元素名: name // startElement, 元素名: size, 属性: units="pt" // characters, 内容: 36 // endElement, 元素名: size // endElement, 元素名: font
-
构建SAX 解析器
SAXParserFactory factory = SAXParserFactory.newInstance () ; SAXParser parser = factory.newSAXParser(); // 处理文档,source 可以是一个文件、一个URL 字符串或者是一个输入流。 // handler 属于DefaultHandler 的一个子类,为以下四个接口定义了空的方法: // ContentHandler // DTDHandler // EntityResolver // ErrorHandler parser.parse(source, handler);
-
startElement 方法有3 个描述元素名的参数,其中 qName 参数以 prefix:localName 的形式报告限定名。如果命名空间处理特性已经打开,那么 uri 和 localName 参数提供的就是命名空间和本地(非限定)名。
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
与DOM 解析器一样,命名空间处理特性默认是关闭的,可以调用工厂类的setNamespaceAware 方法来激活命名空间处理特性
SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); SAXParser saxParser = factory.newSAXParser();
关闭自动下载验证文件
factory.setFeature("http: //WWW.w3.org/TR/xhtml/DTD/xhtml-strict.dtd", false);
-
-
使用StAX 解析器
-
StAX 解析器是一种“拉解析器(pull parser )", 与安装事件处理器不同,你只需使用下面这样的基本循环来迭代所有的事件
InputStream in = url.openStream() ; XMLInputFactory factory = XMLInputFactory.newInstance() ; XMLStreamReader parser= factory.createXMLStreamReader(in); while (parser.hasNext()) { int event = parser.next(); // Call parser to to obtain event details }
-
例子
<font> <name>Helvetica</name> <size units="pt">36</size> </font> // 解析器将产生下面的事件 // START_ELEMENT,元素名:font // CHARACTERS,内容:空白字符 // START_ELEMENT,元素名:name // CHARACTERS,内容:Helvetica // END_ELEMENT,元素名:name // CHARACTERS,内容:空白字符 // START_ELEMENT,元素名:size // CHARACTERS,内容:36 // END_ELEMENT,元素名:size // CHARACTERS,内容:空白字符 // END_ELEMENT,元素名:font
-
要分析这些属性值,需要调用XMLStreamReader 类中恰当的方法
// 获取当前元素的units 属性 String units= parser.getAttributeValue(null, "units");
默认情况下,命名空间处理是启用的,你可以通过像下面这样修改工厂来使其无效
XMLInputFactory factory = XMLInputFactory.newInstance(); factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
-
3.7 生成XML 文档
-
不带命名空间的文档
-
要建立一棵DOM 树,你可以从一个空的文档开始。通过调用DocumentBuilder 类的newDocument 方法可以得到一个空文档。
Document doc = builder.newDocument () ;
-
使用Document 类的createElement 方法可以构建文档里的元素
Element rootElement = doc.createElement(rootName); Element childElement = doc.createElement(childName);
-
使用createTextNode 方法可以构建文本节点
Text textNode = doc.createTextNode(textContents);
-
使用以下方法可以给文档添加根元素,给父结点添加子节点
doc.appendChild(rootElement); rootElement.append(hild(childElement); childElement.appendChild(textNode);
-
调用Element 类的setAttribute方法设置元素属性
rootElement.setAttribute(name, value);
-
-
带命名空间的文档
-
使用命名空间和上面的方法有差距,需要将生成器工厂设置为是命名空间感知的,然后再创建生成器
DocumentBuilderFactoryfactory = DocumentBuilderFactory.newlnstance(); factory.setNamespaceAware(true); builder = factory.newDocumentBuilder();
-
使用createElementNS 而不是createElement 来创建所有节
String namespace = "http://www.w3.org/2000/svg"; Element rootElement = doc.createElementNS (namespace, "svg") ;
-
如果节点具有带命名空间前缀的限定名,那么所有必需的带有xmlns 前缀的属性都会被自动创建。如果需要在HTML 中包含SVG, 那么就可以像下面这样构建元素
Element svgElement = doc.createElement(namespace, "svg:svg") // 当该元素被写入XML 文件时,它会转变 // <svg:svg xmlns:svg="http://www.w3.org/2000/svg">
-
需要设置的元素属性的名字位千命名空间中,那么可以使用Element 类的setAttributeNS 方法
rootElement.setAttributeNS(namespace, qualifiedName, value);
-
-
写出文档
-
把DOM 树写出到输出流中
- 第一种方式,为了将DOCTYPE节点纳入输出,我们还需要将SYSTEM和PUBLIC标识符设置为输出属性。
// construct the do-nothing transformation Transformer t = TransformerFactory.newInstance().newTransformer() ; // set output properties to get a DOCTYPE node t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemldentifier); t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicldentifier); // set indentation t.setOutputPrope rty(OutputKeys.INDENT, "yes"); t.setOutputProperty(OutputKeys.METHOD, "xml "); t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); // apply the do-nothing transformation and send the output to a file t.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(file)));
- 第二种方式,使用LSSerializer 接口
DOMImplementation impl = doc.getImplementation(); DOMImplementationLS implLS = (DOMImplementationLS) impl.getFeature("LS", "3 .0"); LSSerializer ser = implLS.createLSSerializer(); // 需要空格和换行,可以设置下面的标志 ser.getDomConfig().setParameter("format-pretty-print", true); // 将文档转换为字符串 String str = ser.writeToString(doc); // 将输出直接写入到文件中 LSOutput out = implLS.createLSOutput(); out.setEncoding("UTF-8"); out.setByteStream(Files.newOutputStream(path)); ser.write(doc, out);
-
-
示例:生成SVG 文件(P172)
-
使用StAX 写出XML 文档
-
StAX API 使我们可以直接将XML 树写出,如下
//从某个Output Stream 中构建一个XMLStreamWriter XMLOutputFactory factory = XMLOutputFactory.newInstance(); XMLStreamWriter writer = factory.createXMLStreamWriter(out); // 产生XML 文件头 writer.writeStartDocument() writer.writeStartElement(name); // 添加属性 writer.writeAttribute(name, value); // 调用 writeStartElement 添加新的子节点 // 写出字符 writer.writeCharacters(text); // 在写完所有子节点之后调用以下方法关闭当前元素 writer.writeEndElement(); // 写出没有子节点的元素 writer.writeEmptyElement(name); // 在文档的结尾调用以下方法关闭所有打开的元素。 writer.writeEndDocurnent();
-
3.8 XSL 转换
- XSL 转换(X SLT) 机制可以指定将XML 文档转换为其他格式的规则,例如,转换为纯文本、XHTML 或任何其他的XML 格式。
- 将XML转化为其他格式必须提供XSLT 样式表,它描述了XML 文档向某种其他格式转换的规则。
API注释
3.2 解析XML 文档
javax.xml.parsers.DocumentBuilderFactory 1.4
static DocumentBuilderFactorynewinstance()
// 返回DocumentBuilderFactory 类的一个实例。
DoeumentBuilder newDocumentBuilder()
// 返回DocumentBuilder 类的一个实例。
javax.xml.parsers.DocumentBuilder 1.4
Document parse(File f)
Document parse(String url)
Document parse(InputStream in)
// 解析来自给定文件、URL 或输入流的XML 文档,返回解析后的文档。
org.w3c.dom.Document 1.4
Element getDocumentElement()
// 返回文档的根元素。
org.w3c.dom. Element 1.4
String getTagName()
// 返回元素的名字。
String getAttribute(String name)
// 返回给定名字的属性值,没有该属性时返回空字符串。
rg.w3c.dom. Node 1.4**
Nodelist getChildNodes ()
// 返回包含该节点所有子元素的节点列表。
Node getFirstChild()
Node getlastChild()
// 获取该节点的第一个或最后一个子节点,在该节点没有子节点时返回null 。
Node getNextSibling()
Node getpreviousSibling()
// 获取该节点的下一个或上一个兄弟节点,在该节点没有兄弟节点时返回null 。
Node getparentNode()
// 获取该节点的父节点, 在该节点是文档节点时返回null 。
NamedNodeMap getAttributes ()
// 返回含有描述该节点所有属性的Attr 节点的映射表。
String getNodeName()
// 返回该节点的名字。当该节点是Attr 节点时,该名字就是属性名。
String getNodeValue()
// 返回该节点的值。当该节点是Attr 节点时,该值就是属性值。
org.w3c.dom. CharacterData 1.4
String getData()
// 返回存储在节点中的文本。
org.w3c.dom.NodeList 1.4
int getLength()
// 返回列表中的节点数。
Node item(int index)
// 返回给定索引值处的节点。索引值范围在0 到getlength() - 1 之间。
org.w3c.dom. NamedNodeMap 1.4
int getLength()
// 返回该节点映射表中的节点数。
Node item(int index)
// 返回给定索引值处的节点。索引值范围在0 到getlength()-1 之间。
3.3.1 文档类型定义
javax.xml.parsers.DocumentBuilder 1.4
void setEntityResolver(EntityResolver resolver)
// 设置解析器,来定位要解析的XML 文档中引用的实体。
void setErrorHandl er(ErrorHandl er handler)
// 设置用来报告在解析过程中出现的错误和警告的处理器。
org.xml.sax.EntityResolver 1.4
public InputSource resolveEntity(String publicID, String systemID)
// 返回一个输入源,它包含了被给定1D 所引用的数据,或者,当解析器不知道如何解析这个特定名字时,返回null 。如果没有提供公共ID , 那么参数publ icID 可以为null 。
org.xml.sax.InputSource 1.4
InputSource(InputStream in)
InputSource(Reader in)
InputSource(String system ID)
// 从流、读入器或系统ID (通常是相对或绝对URL ) 中构建输入源。
org.xml.sax. ErrorHandler 1.4
void fatalError(SAXParseException exception)
void error(SAXParseException exception)
void warning(SAXParseException exception)
// 覆盖这些方法以提供对致命错误、非致命错误和警告进行处理的处理器。
org.xml.sax.SAXParseException 1.4
int getlineNumber()
int getColumnNumber()
// 返回引起异常的巳处理的输入信息末尾的行号和列号。
javax.xml.parsers.DocumentBuilderFactory 1.4
boolean isValidating()
void setValidating(boolean value)
// 获取和设置工厂的validating 属性。当它设为true 时,该工厂生成的解析器会验证它们的输入信息。
boolean isIgnoringElementContentWhitespace()
void setlgnoringElementContentWhitespace(boolean value)
// 获取和设置工厂的ignoringElementContentWhitespace 属性。当它设为true时,该工厂生成的解析器会忽略不含混合内容( 即,元素与# PCDATA 混合)的元素节点之间的空白字符。
3.4 使用XPath 来定位信患
javax.xml.xpath.XPathFactory 5.0
static XPathFactory newinstance()
// 返回用于创建XPath 对象的XPathFactory 实例。
XPath newXpath()
// 构建用千计算XPath 表达式的XPath 对象。
javax.xml.xpath.XPath 5.0
String evaluate(String expression, Object startingPoint)
// 从给定的起点计算表达式。起点可以是一个节点或节点列表。如果结果是一个节点或节点集, 则返回的字符串由所有文本节点子元素的数据构成。
Object evaluate(String expression, Object startingPoint, QName returnType)
// 从给定的起点计算表达式。起点可以是一个节点或节点列表。resultType 是XPathConstants 类的常量STRING 、NODE 、NODESET 、NUMBER 或BOOLEAN 之一。返回值是String 、Node 、Nodel i st 、Number 或Boolean 。
3.5 使用命名空间
org.w3c.dom.Node 1.4
String getlocalName()
// 返回本地名(不带前缀),或者在解析器不感知命名空间时,返回null 。
String getNamespaceURI()
// 返回命名空间URI ,或者在解析器不感知命名空间时,返回null 。
javax.xml.parsers.DocumentBuilderFactory 1.4
boolean isNamespaceAware()
void setNamespaceAware(boolean value)
// 获取或设置工厂的namespaceAware 属性。当设为true 时,工厂产生的解析器是命名空间感知的。
3.6.1 使用SAX 解析器
javax.xml.parsers.SAXParserFactory 1.4
static SAXParserFactory newInstance()
// 返回SAXParserFactory 类的一个实例。
SAXParser newSAXParser()
// 返回SAXParser 类的一个实例。
boolean isNamespaceAware()
void setNamespaceAware(boolean value)
// 获取和设置工厂的namespaceAware 属性。当设为true 时,该工厂生成的解析器是命名空间感知的。
boolean isValidating()
void setValidating(boolean value)
// 获取和设置工厂的validating 属性。当设为true 时,该工厂生成的解析器将要验证其输入。
javax.xml.parsers.SAXParser 1.4
void parse(File f, DefaultHandler handler)
void parse(String url, DefaultHandler handler)
void parse(InputStream in, Defaul tHandl er handler)
// 解析来自给定文件、URL 或输入流的XML 文档,并把解析事件报告给指定的处理器。
org.xml.sax.ContentHandler 1.4
void startDocument()
void endDocument()
// 在文档的开头和结尾处被调用。
void startElement(String uri, String Iname, String qname, Attributes attr)
void endElement(String uri, String Iname, String qname)
// 在元素的开头和结尾处被调用。
// 参数: uri 命名空间的URI (如果解析器是命名空间感知的)
// Iname 不带前缀的本地名(如果解析器是命名空间感知的)
// qname 元素名(如果解析器是命名空间感知的),或者是带有前缀的限定名(如果解析器除了报告本地名之外还报告限定名)
void characters(char[] data, int start, int length)
// 解析器报告字符数据时被调用。
// 参数: data 字符数据数组
// start 在作为被报告的字符数据的一部分的字符数组中,第一个字符的索引
// length 被报告的字符串的长度
org.xml.sax.Attributes 1.4
int getLength ()
// 返回存储在该属性集合中的属性数量。
String getLocalName(int index)
// 返回给定索引的属性的本地名(无前缀),或在解析器不是命名空间感知的情况下返回空字符串。
Str i ng getURI(int index)
// 返回给定索引的属性的命名空间URI, 或者,当该节点不是命名空间的一部分,或解析器并非命名空间感知时返回空字符串。
String getQName(int index)
// 返回给定索引的属性的限定名(带前缀),或当解析器不报告限定名时返回空字符串。
String getValue(int index)
String getValue(String qname)
String getValue(String uri , String Iname)
// 根据给定索引、限定名或命名空间URI+本地名来返回属性值;当该值不存在时,返回null 。
3.6.2 使用StAX 解析器
javax.xml.stream.XMLInputFactory 6
static XMLinputFactory newInstance()
// 返回XML! nputF actory 类的一个实例。
void setProperty(String name, Object value)
// 设置这个工厂的属性,或者在要设置的属性不支持设置成给定值时,抛出IllegalArgumentException 。Java SE 的实现支持下列Boolean 类型的属性:
// "javax.xml.stream.isValidating 为false (默认值)时,不验证文档(规范不要求必须支持) 。
// "javax.xml.stream.isNamespaceAware" 为true (默认值)时,将处理命名空间(规范不要求必须支持) 。
// "javax.xml.stream.isCoalescing" 为false (默认值)时,邻近的字符数据不进行连接。
// "javax.xml.stream.isReplacingEntityReferences" 为true 默认值)时,实体引用将作为字符数据被替换和报告。
// "javax.xml.stream.isSupportingExtemalEntities" 为true (默认值)时,外部实体将被解析。规范对于这个属性没有给出默认值。
// "javax.xml.stream.supportDTD" 为true (默认值)时, DTD 将作为事件被报告。
XMLStreamReader createXMLStreamReader(InputStream in)
XMLStreamReader createXMLStreamReader(InputStream in , StringcharacterEncoding)
XMLStreamReader createXMLStreamReader(Reader in)
XMLStreamReader createXMLStreamReader(Source in)
// 创建一个从给定的流、阅读器或JAXP 源读入的解析器。
javax.xml.stream.XML StreamReader 6
boolean hasNext()
// 如果有另一个解析事件, 则返回true 。
int next()
// 将解析器的状态设置为下一个解析事件,并返回下列常量之一: START_ELEMENT END_ELEMENT CHARACTERS START_DOCUMENT END_DOCUMENT CDATA COMMENTSPACE(可忽略的空白字符) 、PROCESSING_INSTRUCTION ENTITY_REFERENCE DTD
boolean isStartElement ()
boolean isEndElement()
boolean isCharacters ()
boolean isWhiteSpace ()
// 如果当前事件是一个开始元素、结束元素、字符数据或空白字符, 则返回true 。
QName getName()
String getlocalName()
// 获取在START_ELEMENT 或END_ELEMENT 事件中的元素的名字。
String getText()
// 返回一个CHARACTERS 、COMMENT 或CDATA 事件中的字符,或一个ENTITY_REFERENCE的替换值,或者一个DTD 的内部子集。
int getAttributeCount()
QName getAttributeName(int index)
String getAttributeLocalName(int index)
String getAttributeValue(int index)
// 如果当前事件是START_ELEMENT , 则获取属性数量和属性的名字与值。
String getAttributeValue(String namespaceURI, String name)
// 如果当前事件是START_ELEMENT , 则获取具有给定名称的属性的值。如果namespaceURI为null , 则不检查名字空间。
3.7.4 示例:生成SVG 文件
javax.xml.parsers.DocumentBuilder 1.4
Document newDocument()
// 返回一个空文档。
org.w3c. dom.Document 1.4
Element createElement(String name)
Element createElementNS(String uri , String qname)
// 返回具有给定名字的元素。
Text createTextNode(String data)
// 返回具有给定数据的文本节点。
org.w3c.dom.Node 1.4
Node appendChild(Node chi 1 d)
// 在该节点的子节点列表中追加一个节点。返回被追加的节点。
org.w3c.dom.Element 1.4
void setAttribute(String name, String value)
void setAttributeNS(String uri, String qname, String value)
// 将有给定名字的属性设置为指定的值。
// 参数: uri 名字空间的URI 或null
// qname 限定名。如果有别名前缀,则uri 不能为null
// value 属性值
javax.xml.transform. TransformerFactory 1.4
static TransformerFactory newInstance()
// 返回TransformerFactory 类的一个实例。
Transformer newTransformer()
// 返回Transformer 类的一个实例,它实现了标识符转换(不做任何事情的转换) 。
javax.xml.transform.Transformer 1.4
void setOutputProperty(String name , String value)
// 设置输出属性。标准输出属性参见http : //www.w3.org/TR/xs lt#output , 其中最有用的几个如下示:
// 参数: doctype- publ i c DOCTYPE 声明中使用的公共ID
// doctype-system DOC TYPE 声明中使用的系统ID
// Indent "yes" 或者”no"
// method "xml"、"html" 、“text" 或定制的字符串
void transform(Source from , Result to)
// 转换一个XML 文档。
javax.xml.transform.dom.DOMSource 1.4
DOMSource(Node n)
// 从给定的节点中构建一个源。通常, n 是文档节点。
javax.xml.transform.stream.StreamResult 1.4
StreamResult(Fi le f)
StreamResult(OutputStream out)
StreamResult(Writer out)
StreamResult(String systemID)
// 从文件、流、写出器或系统ID (通常是相对或绝对URL) 中构建流结果。
3.7.5 使用StAX 写出XML 文档
javax.xml.stream.XMLOutputFactory 6
static XMLOutputFactory newInstance()
// 返回XMLOutputFactory 类的一个实例。
XMLStreamWriter createXMLStreamWriter(OutputStream in)
XMLStreamWriter createXMLStreamWriter(OutputStream in, String characterEncoding)
XMLStreamWriter createXMLStreamWriter(Writer in)
XMLStreamWriter createXMLStreamWriter(Result in)
// 创建写出到给定流、写出器或JAXP 结果的写出器。
javax. xml.stream.XMLStreamWriter 6
void writeStartDocument()
void writeStartDocument(String xmlVersion)
void writeStartDocument(String encoding, String xmlVersion)
// 在文档的顶部写入XML 处理指令。注意, encoding 参数只是用于写入这个属性,它不会设置输出的字符编码机制。
void setDefaultNamespace(String namespaceURI)
void setPrefix(String prefix, String namespaceURI)
// 设置默认的命名空间,或者具有前缀的命名空间。这种声明的作用域只是当前元素,如果没有写明具体元素,其作用域为文档的根。
void writeStartElement(String localName)
void writeStartElement(String namespaceURI, String localName)
// 写出一个开始标签, 其中namespaceURI 将用相关联的前缀来代替。
void writeEndElement()
// 关闭当前元素。
void writeEndDocument()
// 关闭所有打开的元素。
void writeEmptyElement(String localName)
void writeEmptyElement( String namespaceURI, String local Name)
// 写出一个自闭合的标签,其中namespaceURI 将用相关联的前缀来代替。
void writeAttribute(String localName, String value)
void writeAttribute(String namespaceURI, String localName, String value)
// 写出一个用于当前元素的属性,其中namespaceURI 将用相关联的前缀来代替。
void writeCharacters(String text)
// 写出字符数据。
void writeCData(String text)
// 写出CDATA 块。
void writeDTD(String dtd)
// 写出dtd 字符串,该字串需要包含一个DOCTYPE 声明。
void writeComment(String comment)
// 写出一个注释。
void close()
// 关闭这个写出器。
3.8 XSL 转换
javax.xml.transform.TransformerFactory 1.4
Transformer newTransformer(Source styleSheet)
// 返回一个transformer 类的实例,用来从指定的源中读取样式表。
javax.xml.transform.stream.StreamSource 1.4
StreamSource(File f)
StreamSource(InputStream in)
StreamSource(Reader in)
StreamSource(String systemID)
// 自一个文件、流、阅读器或系统ID (通常是相对或绝对URL) 构建一个数据流源。
javax.xml.transform.sax.SAXSource 1.4
SAX Source(XMLReader reader, InputSource source)
// 构建一个SAX 数据源,以便从给定输入源中获取数据,并使用给定的阅读器来解析输入数据。
org.xml.sax.XMLReader 1.4
void setContentHandler(ContentHandler handler)
// 设置在输入被解析时会被告知解析事件的处理器。
void parse(InputSource source)
// 解析来自给定输入源的输入数据,并将解析事件发送到内容处理器。
javax.xml.transform.dom.DOMResult 1.4
DOMResult(Node n)
// 自给定节点构建一个数据源。通常, n 是一个新文档节点。
org.xml.sax.helpers.Attributeslmpl 1.4
void addAttribute(String uri , String lname, String qname, String type, String value)
// 将一个属性添加到该属性集合。
// 参数: uri 名字空间的URI
// lname 无前缀的本地名
// qname 带前缀的限定名
// type 类型,“CDATA"、“ID"、“IDREF"、“IDREFS"、“NMTOKEN"、“NMTOKENS”、“ENTITY”、 “ENTITIES" 或“NOTATION" 之一
// value 属性值
void clear()
// 删除属性集合中的所有属性。
评论区