转:XML 中的空白字符须知:xml:space
了解 XML 空白字符的概念并掌握如何避免与之相关的问题的技巧。
2006 年 4 月发布
很多时候,您可能都没注意到,在 XML 中所做的更改影响着您访问 XML 文档中数据的方式。例如:
<Author><FirstName>John</FirstName> <LastName>Smith</LastName></Author>
完全不同于
<Author> <FirstName>John</FirstName> <LastName>Smith</LastName> </Author>
以下是一个完整的示例(请参阅示例代码中的示例 1):假设您希望使用 DOM API 获取 <Author> 的第一个子元素,如下所示:
XMLDocument doc = parser.getDocument(); Element elem = doc.getDocumentElement(); Node node = elem.getFirstChild();
利用 Oracle XDK DOM 分析器的默认设置,第一个文档返回 <FirstName> 的同时,第二个文档返回一个为空白字符节点的文本节点。
同样,有时 XSLT 转换不会生成您预期的结果。(请参阅示例 2。)XML 文档需要使用 XSLT 进行转换。XSL 样式表使用 position() 函数来为 <Chapter> 和 <Section> 元素创建排序信息:
<?xml version="1.0"?> <Book> <Chapter> <Section/> <Section/> <Section/> </Chapter> <Chapter> <Section/> <Section/> <Section/> </Chapter> </Book>
然而,以下 XSL 样式表:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/>
<xsl:template match="*"> <xsl:element name="{local-name()}"> <xsl:attribute name="Position"> <xsl:value-of select="position()"/> </xsl:attribute> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> </xsl:stylesheet>
并不会按期望运行,它将产生以下结果:
<?xml version = '1.0' encoding = 'UTF-8'?> <Book Position="1"> <Chapter Position="2"> <Section Position="2"/> <Section Position="4"/> <Section Position="6"/> </Chapter> <Chapter Position="4"> <Section Position="2"/> <Section Position="4"/> <Section Position="6"/> </Chapter> </Book>
位置不正确是由空白字符造成的。如果在 XSLT 转换中调用 position() 函数删除之前使用以下样式表删除空白字符:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
将生成期望的结果:
<?xml version = '1.0' encoding = 'UTF-8'?> <Book Position="1"> <Chapter Position="1"> <Section Position="1"/> <Section Position="2"/> <Section Position="3"/> </Chapter> <Chapter Position="2"> <Section Position="1"/> <Section Position="2"/> <Section Position="3"/> </Chapter> </Book>
对于此例,如果不希望删去所有 XML 元素的空白字符,可使用 <xsl:strip-space element="Book,Chapter, Section"> 代替。
以下部分将介绍 XML 空白字符的概念以及避免此类问题的技巧。
什么是 XML 空白字符?
XML 将以下四种字符归为空白字符:回车符(\r 或 ch(13))、换行符(\n 或 ch(10))、制表符 (\t) 以及空格 (' ')。在 XML 文档中,空白字符分为两类:
- 有意义空白字符 是文档内容的一部分,应予以保留。
- 无意义空白字符 在编辑 XML 文档时使用,以增加可读性。这些空白字符一般在文档交付时不予保留。
通常,若没有 DTD (文档类型定义(Document Type Definition)是一套为了进行程序间的数据交换而建立的关于标记符的语法规则)或 XML 模式定义,所有空白字符都是有意义空白字符,应当保留。然而,如果有 DTD 或 XML 模式定义,则只有以下内容中的空白字符有意义:
<sig> ------------------ John Smith Product Manager Example.com -------------------- </sig>
XML 处理器如何处理 XML 空白字符
XML 标准详细说明了 XML 处理器应如何处理空白字符。
XML 分析:XML 规范提供了一个内置属性 xml:space 来告知 XML 分析器其是否应忽略空白字符。该属性由其根元素的子元素来继承。声明时,必须将其指定为枚举类型,其可能的值只能是“ default”和“ preserve”。如果指定为“ preserve”,则所定义元素内的空白字符必须保留。
根据 W3C XML 规范,默认情况下,Oracle XML 开发人员工具包 (XDK) XML 分析器将保留所有空白字符。因此, xml:space =“ default”或 xml:space =“ preserve ”将具有相同的作用:保留空白字符。若要避免保留空白字符,需要按如下所示设置 Oracle XDK 分析器:
XDK DOM Parser:
DOMParser parser = new DOMParser(); parser.setPreserveWhitespace(false);
SAX Parser:
SAXParser parser = new SAXParser(); parser.setPreserveWhitespace(false);
XSLT 转换。W3C XSLT 规范提供了两个元素(即 xsl:strip-space 和 xsl:preserve-spacea€”)来处理空白字符。 xsl:strip-space 指定了应删除空白字符文本节点(即文本节点完全由空白字符组成)的 XML 元素。请注意, xsl:strip-space 只有影响纯空白字符的节点。 xsl:strip-space 可以列为一组由空白字符或使用通配符(例如 *)隔开的元素。 xsl:preserve-space 具有类似的语法,但执行的结果却与 xsl:strip-space 正好相反。
以下示例(请参阅示例 3)应用了一个复制源文档的 XSL 样式表,但删去了空白字符文本节点:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
对于如下所示的 XML 文档:
<rootElement> <childElement test="true"> Value </childElement>This is the test <childElement test="true" xml:space="preserve"> Value </childElement> <childElement xml:space="preserve"> </childElement> <childElement> </childElement> </rootElement>
XSLT 转换将生成以下结果:
<rootElement><childElement test="true"> Value </childElement>This is the test <childElement test="true" xml:space="preserve"> Value </childElement><childElement xml:space="preserve"> </childElement><childElement/></rootElement>
您可能注意到,如果 XML 元素中的 xml:space=" preserved" ,则不会删去空白字符。这种行为基于 XSLT 规范,该规范定义了保留空白字符的条件:
文本节点的父元素具有的 xml:space 属性值为 preserve,并且没有更近的父元素具有带有默认值的 xml:space。
XSLT 还提供 normalize-space() 函数,将包含多个空白字符的字符串转换为一个空白字符,从作为参数传递给它的字符串删除所有前导空白字符和尾随空白字符。
DOM 序列化。序列化 XML 文档时,输出缩进将添加无意义空白字符。默认情况下,Oracle XDK DOM 分析器将以缩进格式打印 XML DOM 文档。
要避免缩进, 在 XDK 9i 中,可将 oracle.xml.parser.v2.XMLPrintDriver 类划分为子类,如下所示(请参阅示例 4):
import oracle.xml.parser.v2.XMLPrintDriver; import oracle.xml.parser.v2.XMLOutputStream;
class MyXMLPrintDriver extends XMLPrintDriver { public MyXMLPrintDriver(java.io.OutputStream A) { super(A); out.setOutputStyle(XMLOutputStream.COMPACT); } }
在 Oracle XDK 10g 中,新增了一个函数 oracle.xml.parser.v2.XMLPrintDriver.setFormatPrettyPrint(),可用于避免执行子类划分操作。使用 Oracle XDK 10g,您可以打印不带缩进的 XML DOM 文档,如下所示(请参阅示例 5):
XMLPrintDriver myprint = new XMLPrintDriver(System.out); myprint.setFormatPrettyPrint(false); Xml_doc.print(myprint);
结论
现在,利用这些基本知识,您可以成功避免由 XML 文档中的空白字符引发的问题。
原链接:http://www.oracle.com/technetwork/cn/topics/xml/wang-whitespace-095149-zhs.html