使用 XPathNavigator 访问强类型 XML 数据

作为 XPath 2.0 数据模型的实例,XPathNavigator 类可以包含映射到公共语言运行库 (CLR) 类型的强类型数据。 根据 XPath 2.0 数据模型,只有元素和属性可以包含强类型化数据。 该XPathNavigator类提供用于将对象XPathDocumentXmlDocument中的数据作为强类型数据访问的机制,以及从一种数据类型转换为另一种数据类型的机制。

通过 XPathNavigator 公开的类型信息

XML 1.0 数据在技术上没有类型,除非使用 DTD、XML 架构定义语言(XSD)架构或其他机制进行处理。 有许多类别的类型信息可以与 XML 元素或属性相关联。

  • 简单的 CLR 类型:XML 架构语言都不支持直接公共语言运行时 (CLR) 类型。 由于能够将简单元素和属性内容视为最合适的 CLR 类型非常有用,因此在缺少架构信息时,所有简单内容都可以被视为 String 类型,而任何添加的架构信息都可能会将此内容优化为更合适的类型。 可以使用该 ValueType 属性找到与简单元素和属性内容的最佳匹配 CLR 类型。 有关从架构内置类型到 CLR 类型的映射的详细信息,请参阅 System.Xml 类中的类型支持

  • 简单 (CLR) 类型列表:包含简单内容的元素或属性可以包含用空格分隔的值列表。 这些值由 XML 架构指定为“列表类型”。如果没有 XML 架构,此类简单内容将被视为单个文本节点。 当 XML 架构可用时,可以将此简单内容公开为一系列原子值,每个值都具有映射到 CLR 对象的集合的简单类型。 有关从架构内置类型到 CLR 类型的映射的详细信息,请参阅 System.Xml 类中的类型支持

  • 类型化值:具有简单类型的架构验证属性或元素具有类型化值。 此值是基元类型,例如数字、字符串或日期类型。 XSD 中的所有内置简单类型均可以映射到 CLR 类型,通过 CLR 类型可以以更适合的类型(而不只是以 String)访问节点的值。 具有属性或元素子级的元素被视为复杂类型。 包含简单内容(只有文本节点作为子级)的复杂类型的类型化值与其内容的简单类型的类型化值相同。 具有复杂内容的复杂类型的类型化值(一个或多个子元素)是其所有子文本节点串联后的字符串值,呈现为String。 有关从架构内置类型到 CLR 类型的映射的详细信息,请参阅 System.Xml 类中的类型支持

  • Schema-Language 特定类型名称:在大多数情况下,CLR 类型由于应用外部架构而被设置,并用于提供对节点值的访问。 但是,在某些情况下,可能需要检查与应用于 XML 文档的特定架构关联的类型。 例如,可能希望搜索 XML 文档,根据附加的架构提取确定包含“PurchaseOrder”类型内容的所有元素。 此类类型信息只能通过模式验证设置结果获得,并且这些信息通过XmlType类的SchemaInfoXPathNavigator属性访问。 有关详细信息,请参阅下面的“后置架构验证信息集”(PSVI)部分。

  • Schema-Language 特定类型反射:在其他情况下,你可能希望获取应用于 XML 文档的架构特定类型的详细信息。 例如,读取 XML 文件时,可能需要提取 maxOccurs XML 文档中每个有效节点的属性,以便执行一些自定义计算。 由于此信息只能通过架构验证进行设置,因此可通过 SchemaInfo 类的属性 XPathNavigator 访问此信息。 有关详细信息,请参阅下面的“后置架构验证信息集”(PSVI)部分。

XPathNavigator 类型化访问器

下表显示了可用于访问有关节点的类型信息的类的各种属性和方法 XPathNavigator

资产 DESCRIPTION
XmlType 该信息包含节点的 XML 架构类型信息(如果节点有效)。
SchemaInfo 此属性包含在验证之后添加的节点的后架构验证信息集。 这包括 XML 架构类型信息以及有效性信息。
ValueType 节点的类型化值的 CLR 类型。
TypedValue 节点的内容为一个或多个 CLR 值,其类型与节点的 XML 架构类型最接近。
ValueAsBoolean 当前节点的 String 值根据 Boolean 的 XPath 2.0 强制转换规则强制转换为 xs:boolean 值。
ValueAsDateTime 当前节点的 String 值根据 DateTime 的 XPath 2.0 强制转换规则强制转换为 xs:datetime 值。
ValueAsDouble 当前节点的 String 值根据 Double 的 XPath 2.0 强制转换规则强制转换为 xsd:double 值。
ValueAsInt 当前节点的 String 值根据 Int32 的 XPath 2.0 强制转换规则强制转换为 xs:integer 值。
ValueAsLong 当前节点的 String 值根据 Int64 的 XPath 2.0 强制转换规则强制转换为 xs:integer 值。
ValueAs 节点内容根据 XPath 2.0 强制转换规则强制转换为目标类型。

有关从架构内置类型到 CLR 类型的映射的详细信息,请参阅 System.Xml 类中的类型支持

后架构验证信息集 (PSVI)

XML 架构处理器接受 XML 信息集作为输入,并将其转换为后模式验证信息集(PSVI)。 PSVI 是原始输入 XML 信息集,其中添加了新信息项,以及添加到现有信息项的新属性。 PSVI 向 XML Infoset 中添加了三类广泛的信息,这些信息由 XPathNavigator 显示。

  1. 验证结果:有关元素或属性是否已成功验证的信息。 此信息通过 Validity 类的 SchemaInfo 属性的 XPathNavigator 属性公开。

  2. 默认信息:指示是否通过架构中指定的默认值获取元素或特性的值。 此信息通过 IsDefault 类的 SchemaInfo 属性的 XPathNavigator 属性公开。

  3. 类型注释:对可能是类型定义或元素和属性声明的架构组件的引用。 该 XmlType 的属性 XPathNavigator 包含节点的特定类型信息(如果该节点有效)。 如果一个节点的有效性未知,例如该节点在验证后又被编辑。 然后,XmlType 属性被设置为 null,但类型信息仍然可以从 SchemaInfo 类的 XPathNavigator 属性的各种性质中获取。

下面的示例演示了如何使用由 XPathNavigator 公开的 Post Schema Validation Infoset 中的信息。

Dim settings As XmlReaderSettings = New XmlReaderSettings()  
settings.Schemas.Add("http://www.contoso.com/books", "books.xsd")  
settings.ValidationType = ValidationType.Schema  
  
Dim reader As XmlReader = XmlReader.Create("books.xml", settings)  
  
Dim document As XmlDocument = New XmlDocument()  
document.Load(reader)  
Dim navigator As XPathNavigator = document.CreateNavigator()  
navigator.MoveToChild("books", "http://www.contoso.com/books")  
navigator.MoveToChild("book", "http://www.contoso.com/books")  
navigator.MoveToChild("published", "http://www.contoso.com/books")  
  
Console.WriteLine(navigator.SchemaInfo.SchemaType.Name)  
Console.WriteLine(navigator.SchemaInfo.Validity)  
Console.WriteLine(navigator.SchemaInfo.SchemaElement.MinOccurs)  
XmlReaderSettings settings = new XmlReaderSettings();  
settings.Schemas.Add("http://www.contoso.com/books", "books.xsd");  
settings.ValidationType = ValidationType.Schema;  
  
XmlReader reader = XmlReader.Create("books.xml", settings);  
  
XmlDocument document = new XmlDocument();  
document.Load(reader);  
XPathNavigator navigator = document.CreateNavigator();  
navigator.MoveToChild("books", "http://www.contoso.com/books");  
navigator.MoveToChild("book", "http://www.contoso.com/books");  
navigator.MoveToChild("published", "http://www.contoso.com/books");  
  
Console.WriteLine(navigator.SchemaInfo.SchemaType.Name);  
Console.WriteLine(navigator.SchemaInfo.Validity);  
Console.WriteLine(navigator.SchemaInfo.SchemaElement.MinOccurs);  

该示例将 books.xml 文件作为输入。

<books xmlns="http://www.contoso.com/books">  
    <book>  
        <title>Title</title>  
        <price>10.00</price>  
        <published>2003-12-31</published>  
    </book>  
</books>  

该示例还采用 books.xsd 架构作为输入。

<xs:schema xmlns="http://www.contoso.com/books"
attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://www.contoso.com/books"
xmlns:xs="http://www.w3.org/2001/XMLSchema">  
    <xs:simpleType name="publishedType">  
        <xs:restriction base="xs:date">  
            <xs:minInclusive value="2003-01-01" />  
            <xs:maxInclusive value="2003-12-31" />  
        </xs:restriction>  
    </xs:simpleType>  
    <xs:complexType name="bookType">  
        <xs:sequence>  
            <xs:element name="title" type="xs:string"/>  
            <xs:element name="price" type="xs:decimal"/>  
            <xs:element name="published" type="publishedType"/>  
        </xs:sequence>  
    </xs:complexType>  
    <xs:complexType name="booksType">  
        <xs:sequence>  
            <xs:element name="book" type="bookType" />  
        </xs:sequence>  
    </xs:complexType>  
    <xs:element name="books" type="booksType" />  
</xs:schema>  

使用 ValueAs 属性获取类型化值

节点的类型化值可以通过访问 TypedValueXPathNavigator 属性进行检索。 在某些情况下,可能需要将节点的类型化值转换为其他类型。 一个常见示例是从 XML 节点获取数值。 例如,请考虑以下未经验证和非类型化的 XML 文档。

<books>  
    <book>  
        <title>Title</title>  
        <price>10.00</price>  
        <published>2003-12-31</published>  
    </book>  
</books>  

如果XPathNavigator位于price元素上,则XmlType属性将是nullValueType属性将是String,并且TypedValue属性将是字符串10.00

但是,仍可以使用ValueAsValueAsDoubleValueAsIntValueAsLong方法和属性将值提取为数值。 以下示例说明如何使用 ValueAs 方法执行此类强制转换。

Dim document As New XmlDocument()  
document.Load("books.xml")  
Dim navigator As XPathNavigator = document.CreateNavigator()  
navigator.MoveToChild("books", "")  
navigator.MoveToChild("book", "")  
navigator.MoveToChild("price", "")  
  
Dim price = navigator.ValueAs(GetType(Decimal))  
Dim discount As Decimal = 0.2  
  
Console.WriteLine("The price of the book has been dropped 20% from {0:C} to {1:C}", navigator.Value, (price - price * discount))  
XmlDocument document = new XmlDocument();  
document.Load("books.xml");  
XPathNavigator navigator = document.CreateNavigator();  
navigator.MoveToChild("books", "");  
navigator.MoveToChild("book", "");  
navigator.MoveToChild("price", "");  
  
Decimal price = (decimal)navigator.ValueAs(typeof(decimal));  
  
Console.WriteLine("The price of the book has been dropped 20% from {0:C} to {1:C}", navigator.Value, (price - price * (decimal)0.20));  

有关从架构内置类型到 CLR 类型的映射的详细信息,请参阅 System.Xml 类中的类型支持

另请参阅