** 分析属性值 **
大部分情况下,属性值都是一个简单的文本字符串。然而,这并不意味着实际应用中的属性值都是字符型的。有时候,属性值是由许多种类型的数据组合而成的,例如 Date 或 Boolean, 这时,你就要用 XmlConvert 或 System.Convevt 类的方法把这些类型转换成原来的类型。 XmlConvert 和 System.Convevt 类都能实现数据类型的转换,但是 XmlConvert 类依据 XSD 中指定的数据类型进行转换,而不管它现在是什么类型。
假设你有以下的 XML 数据片断:
1<person birthday="2-8-2001"></person>
让我们先确认, birthdaay 属性值是 February 8, 2001, 如果你用 System.Convert 类把该字符串转换成 .NET Framework 中的 DateTime 类型,这样,我们就可以把它当成 date 类型使用了。相比下,如果你用 XmlConvert 类来转换字符串,你将看到一个分析错误,因为 XmlConvert 类不能正确解释这个字符串中的日期。因为在 XML 中,日期型数据的格式必须是 YYYY-MM-DD 形式的。 XmlConvert 类担任 CLR 类型与 XSD 类型之间的相互转换工作。当转换工作发生时,转换结果是局部的。
在某些解决方案中,属性值是由纯文本和实体共同组成的。在所有的阅读器类中,只有 XmlValidatingReader 类能处理实体。 XmlTextReader 虽然不能处理实体,但它们同时出现在属性值中的时候,它只能把文本值取出来。出现这种情况,你必须用 ReadAttributeValue 方法替代简单的读方法来分析属性值的内容。
ReadAttributeValue 方法分析属性值 , 然后把各个组成的要素分隔开(如把纯文本和实体分开)。你可以用 ReadAttributeValue 方法的返回值作为循环条件,遍历整个属性值中的要素。既然 XmlTextReader 类不能处理实体,那么你可以自己写一个用于处理实体的类。下面的代码片断演示了怎么调用一个自定义的处理类:
while(reader.ReadAttributeValue())
{
if (reader.NodeType == XmlNodeType.EntityReference)
// Resolve the "reader.Name" reference and add
// the result to a buffer
buf += YourResolverCode(reader.Name);
else
// Just append the value to the buffer
buf += reader.Value;
}
当属性值全部被分析后, ReadAtributeValue 方法返回 False, 从而结束循环。属性值的最终结果就是全局变量 buffer 的值了。
** 处理 XML ** ** 文本 (Text) **
当我们在处理 XML 标签文本时,如果不能正确的处理,它的错误原因能很快地确定。例如一个字符转换错误,它必然是传输了非 XML 文本到一个 XML 数据流中。不是所有在给定的平台中有效的字符都是有效的 XML 字符。只有在 XML 规范 (www.w3.org/TR/2000/REC-xml-20001006.html) 中规定的有效的字符才能安全的用作元素和属性名。
XmlConvert 类提供了把非 XML 标准的命名转换成标准的 XML 命名的功能。当标签名中包含有无效的 XML 字符时, EncodeName 和 DecodeName 方法能把它们调整成符合 Schema 的 XML 命名。包括 SQL Server™ 和 Microsoft Office ,这些应用程序允许及支持 Unicode 文档,然而,这些文档中的字符有些也不是有效的 XML 命名。典型的情况是在你处理数据库中包含空格的列名时。虽然 SQL Server 允许长列名,但这对 XML 流来说可能就不是有效的命名。空格会被十六进制代码 Invoice_0x0020_Details 替代。下面的代码演示了怎么样在程序中获得该字符串:
XmlConvert.EncodeName("Invoice Details");
与此相反的方法是 DecodeName 。该方法把 XML 文本转换成其原始的格式。要注意的是它只能转换完整的十六进制代码,只有 0x0020 才被当成一个空格,而 0x20 就不是了:
XmlConvert.DecodeName("Invoice_0x0020_Details");
在 XML 文档中的空格即重要也不重要。说它重要,是当它出现在元素的内容中或者它在注释语句中时 , 它能表示实际意义。例如下面的情况:
1<mynode xml:space="preserve">
2<!-- any space here must be preserved -->
3
4•••
5
6</mynode>
在 xml 中,空格不只是代表空格(空白),也代表回车、换行和缩进。
通过 XmlTextReader 类的 WhiteSpaceHandling 属性你可以处理空格。这个属性接受及返回一个 WhiteSpaceHandling 枚举值 ( 该枚举类有三种可选值 ) 。默认值是 All, 它表示有意义和无意义的空格都会作为节点返回 ---- 分别为 SignificantWhitespace 和 Whitespace 节点。 另一个枚举值是 None, 它表示对任何空格都不作为节点返回。最后,就是 Signficant 枚举值 , 它表示忽略没有意义的空格,而只返回节点类型为 SignficantWhitespace 的节点。注意 WhiteSpaceHandling 属性是少数阅读器属性中的一个。它能被改变在任何时候和给 Read 操作带来影响。而 Normalization 及 XmlResolver 属性是“ Sensitive” 的。
** String ** ** 和 ** ** Fragment **
程序员把在 MSXML 的程序剪切下来,会发现在 COM 和 .NET Framework XML API 之间的差别很大。 .NET Framework 类本身没有提供方法去分析存储在字符串中 XML 数据。不像 MSXML 分析器对象, XmlTestReader 类没有提供任何一种 LoadXML 方法从一个格式良好的字符中创建阅读器。没有提供类似 LoadXML 的方法因为你可以用特殊的 text reader---StringReader 类来获得同样的功能。
XmlTextReader 其中一个构造函数接受一个 TextReader 派生对象和一个 XML reader 作参数 ( 该阅读器以 text reader 的内容为基础创建 ) 。一个 text reader 类是一个流,这个流是输入的字符经优化生成的。 StringReader 类继承 TextReader 类,并用一个内存中字符串作为其输入流。下面的代码片断演示了怎样初始化一个 XML reader ,用一个格式良好的 XML 字符串作为其输入:
string xmlText = "...";
StringReader strReader = new StringReader(xmlText);
XmlTextReader reader = new XmlTextReader(strReader);
另外,用 StringWriter 类代替 TextWrite 类,你可以从内存字符中创建一个 XML 文档。
一个指定类型的 XML 字符串是一个 XML 片断( fragment ) . XML 片断由 XML 文本构成,但没有根节点的 XML 文档不是格式良好的 XML 文档,所以不能被应用。一个 XML 片断是原始的文档的一部分,所以它可能缺少根节点。例如,下面的 XML 文本是一个有效的 XML 片断,但不是一个有效的 XML 文档,因为它没有根节点:
1<firstname>Dino</firstname>
1<lastname>Esposito</lastname>
.NET Framework XML API 允许程序员把 XML 片断与一个分析器内容结合使用,分析器内容由类似 encoding 字符集, DTD 文档,命名空间,语言和空格处理程序构成:
public XmlTextReader(
string xmlFragment,
XmlNodeType fragType,
XmlParserContext context
);
xmlFragment 参数包括了 XML 字符串分析。 FragType 参数表示 fragment 的类型,它给出了 fragment 根节点的类型。只有 element,attibute 和 document 类型的节点才能作为 fragment 的根节点,分析器的内容才能被 XmlParserContext 类解释。