Accessing Strongly Typed XML Data Using XPathNavigator
As an instance of the XPath 2.0 data model, the XPathNavigator class can contain strongly typed data that maps to common language runtime (CLR) types. According to the XPath 2.0 data model, only elements and attributes can contain strongly typed data. The XPathNavigator class provides mechanisms for accessing data within an XPathDocument or XmlDocument object as strongly typed data as well as mechanisms for converting from one data type to another.
Type Information Exposed by XPathNavigator
XML 1.0 data is technically without type, unless processed with a DTD, XML schema definition language (XSD) schema, or other mechanism. There are a number of categories of type information that can be associated with an XML element or attribute.
Simple CLR Types: None of the XML Schema languages support Common Language Runtime (CLR) types directly. Because it is useful to be able to view simple element and attribute content as the most appropriate CLR type, all simple content can be typed as String in the absence of schema information with any added schema information potentially refining this content to a more appropriate type. You can find the best matching CLR type of simple element and attribute content by using the ValueType property. For more information about the mapping from schema built-in types to CLR types, see Type Support in the System.Xml Classes.
Lists of Simple (CLR) Types: An element or attribute with simple content can contain a list of values separated by white space. The values are specified by an XML Schema to be a "list type." In the absence of an XML Schema, such simple content would be treated as a single text node. When an XML Schema is available, this simple content can be exposed as a series of atomic values each having a simple type that maps to a collection of CLR objects. For more information about the mapping from schema built-in types to CLR types, see Type Support in the System.Xml Classes.
Typed Value: A schema-validated attribute or element with a simple type has a typed value. This value is a primitive type such as a numeric, string, or date type. All the built-in simple types in XSD can be mapped to CLR types that provide access to the value of a node as a more appropriate type instead of just as a String. An element with attributes or element children is considered to be a complex type. The typed value of a complex type with simple content (only text nodes as children) is the same as that of the simple type of its content. The typed value of a complex type with complex content (one or more child elements) is the string value of the concatenation of all its child text nodes returned as a String. For more information about the mapping from schema built-in types to CLR types, see Type Support in the System.Xml Classes.
Schema-Language Specific Type Name: In most cases, the CLR types, which are set as a side-effect of applying an external schema, are used to provide access to the value of a node. However, there may be situations where you may want to examine the type associated with a particular schema applied to an XML document. For example, you may wish to search through an XML document, extracting all elements that are determined to have content of type "PurchaseOrder" according to an attached schema. Such type information can be set only as a result of schema validation and this information is accessed through the XmlType and SchemaInfo properties of the XPathNavigator class. For more information, see The Post Schema Validation Infoset (PSVI) section below.
Schema-Language Specific Type Reflection: In other cases, you may want to obtain further details of the schema-specific type applied to an XML document. For example, when reading an XML file, you may want to extract the
maxOccurs
attribute for each valid node in the XML document in order to perform some custom calculation. Because this information is set only through schema validation, it is accessed through the SchemaInfo property of the XPathNavigator class. For more information, see The Post Schema Validation Infoset (PSVI) section below.
XPathNavigator Typed Accessors
The following table shows the various properties and methods of the XPathNavigator class that can be used to access the type information about a node.
Property | Description |
---|---|
XmlType | This contains the XML schema type information for the node if it is valid. |
SchemaInfo | This contains the Post Schema Validation Infoset of the node that is added after validation. This includes the XML schema type information, as well as validity information. |
ValueType | The CLR type of the typed value of the node. |
TypedValue | The content of the node as one or more CLR values whose type is the closest match to the XML schema type of the node. |
ValueAsBoolean | The String value of the current node cast to a Boolean value, according to the XPath 2.0 casting rules for xs:boolean . |
ValueAsDateTime | The String value of the current node cast to a DateTime value, according to the XPath 2.0 casting rules for xs:datetime . |
ValueAsDouble | The String value of the current node cast to a Double value, according to the XPath 2.0 casting rules for xsd:double . |
ValueAsInt | The String value of the current node cast to a Int32 value, according to the XPath 2.0 casting rules for xs:integer . |
ValueAsLong | The String value of the current node cast to a Int64 value, according to the XPath 2.0 casting rules for xs:integer . |
ValueAs | The contents of the node cast to the target type according to the XPath 2.0 casting rules. |
For more information about the mapping from schema built-in types to CLR types, see Type Support in the System.Xml Classes.
The Post Schema Validation Infoset (PSVI)
An XML Schema processor accepts an XML Infoset as input and converts it into a Post Schema Validation Infoset (PSVI). A PSVI is the original input XML infoset with new information items added and new properties added to existing information items. There are three broad classes of information added to the XML Infoset in the PSVI that are exposed by the XPathNavigator.
Validation Outcomes: Information as to whether an element or attribute was successfully validated or not. This is exposed by the Validity property of the SchemaInfo property of the XPathNavigator class.
Default Information: Indications as to whether the value of the element or attribute was obtained via default values specified in the schema or not. This is exposed by the IsDefault property of the SchemaInfo property of the XPathNavigator class.
Type Annotations: References to schema components that may be type definitions or element and attribute declarations. The XmlType property of the XPathNavigator contains the specific type information of the node if it is valid. If the validity of a node is unknown, such as when it was validated then subsequently edited. then the XmlType property is set to
null
but type information is still available from the various properties of the SchemaInfo property of the XPathNavigator class.
The following example illustrates using information in the Post Schema Validation Infoset exposed by the XPathNavigator.
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);
The example takes the books.xml
file as input.
<books xmlns="http://www.contoso.com/books">
<book>
<title>Title</title>
<price>10.00</price>
<published>2003-12-31</published>
</book>
</books>
The example also takes the books.xsd
schema as input.
<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>
Obtain Typed Values Using ValueAs Properties
The typed value of a node can be retrieved by accessing the TypedValue property of the XPathNavigator. In certain cases you may want to convert the typed value of a node to a different type. A common example is to get a numeric value from an XML node. For example, consider the following unvalidated and untyped XML document.
<books>
<book>
<title>Title</title>
<price>10.00</price>
<published>2003-12-31</published>
</book>
</books>
If the XPathNavigator is positioned on the price
element the XmlType property would be null
, the ValueType property would be String, and the TypedValue property would be the string 10.00
.
However, it is still possible to extract the value as a numeric value using the ValueAs, ValueAsDouble, ValueAsInt, or ValueAsLong method and properties. The following example illustrates performing such a cast using the ValueAs method.
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));
For more information about the mapping from schema built-in types to CLR types, see Type Support in the System.Xml Classes.