XML in the Microsoft .NET Framework
Borland Developers Conference 2004
Authored by Robert
Love
Introduction.. 2
Reading an
XML Document.. 2
Reading with
XmlReader Descendants. 2
Reading with
XmlDocument 5
Reading with
XmlDataDocument 7
Reading with
the XPathNavigator Class. 7
Writing an
Xml Document.. 9
Writing with
XmlWriter 9
Writing with
XmlDocument 10
Writing with
XmlDataDocument 11
Xml Object
Serialization.. 12
What is
Object Serialization?. 12
How to use
XmlSerializer 12
Controlling
Serialization through Attributes. 14
Performing
XSLT Transformations.. 15
Tools.. 15
Appendix.. 17
Training
Example Xml Document 17
XPath. 17
Getting
Started with XPath. 17
Relative
Paths. 18
Path
Wildcards. 19
Current and
Prior Node. 20
XPath Axes. 21
XPath
Predicates. 22
Accessing
Attributes. 23
XPath
Expression. 24
XPath
Functions. 26
XSLT.. 29
XSLT
Declaration. 29
Matching and
Applying Templates. 29
value-of
element 31
for-each
element 32
Extending
Templates. 33
Recommended
References.. 35
Contact
Information.. 36
XML has become an industry standard and is universally
accepted. It is used in a number of different ways. The .NET framework is no
exception. There are many different and unique ways XML is used in the .NET
Framework. This document will attempt to show some common XML tasks, and how
to address these using the classes in the framework.
There are many built-in ways to read an Xml Document, each with
its own benefits. Understanding these benefits and associated drawbacks, will
help you in determining which class is the correct one to use.
Some of the ways to read an Xml Document in the .NET
Framework
- The Abstract XmlReader Class Descendants
- XmlTextReader
- XmlValidatingReader
- XmlNodeReader
- The XmlDocument Class and Descendants
- The XPathDocument Class
- The ReadXml Method of Dataset
- Classes in System.Xml.Serialization Namespace
XmlReader provides an abstract model for accessing Xml
Data. XmlReader descendants provide a Read Only, Uni-Directional view of an
Xml Document. They also provide an easy interface to walk an Xml document
from beginning to end.
There are three built in XmlReader Descendants
|
Class
|
Purpose
|
|
XmlTextReader
|
Read an Xml document stream or file with out validating to
a schema or a Document Type Definition (DTD).
|
|
XmlNodeReader
|
Read from an XmlNode descendant such as XmlDocument which
is the .NET DOM Implementation.
|
|
XmlValidatingReader
|
Read an Xml Document Stream or File, allowing it to be validated
to a schema or a Document Type Definition (DTD).
|
When using XmlTextReader or XmlValidatingReader you can keep
your memory footprint lower, since the entire document does not need to be
loaded in memory. This makes these classes very useful for large files where
the file size is greater than the available memory. The XmlNodeReader does
not have this benefit as it is reading from an XmlNode descendant. Typically
this XmlNode is an XmlDocument which already has loaded the entire document in
to memory.
The XmlReader provides several methods to assist you in walking
through all parts of an Xml Document. Each of these is very well documented in
the .NET SDK Help File. I dont intend to cover all of these, only the essential
methods needed to do basic parsing.
When reading with an XmlReader each part of the Xml document
is separated in to a node. For example, the following XML structure would be
broken into five different nodes.
<example><name>value</name></example>
|
Document Part
|
Node Type
|
|
<example>
|
XmlNodeType.Element
|
|
<name>
|
XmlNodeType.Element
|
|
Value
|
XmlNodeType.Text
|
|
</name>
|
XmlNodeType.EndElement
|
|
</example>
|
XmlNodeType.EndElement
|
When constructing an instance of an XmlReader descendant you
specify the source of the Xml Document. In the case of XmlTextReader you have
many different overloaded constructors allowing you to specify many different
types of sources, such as the file name or stream that contains the Xml
document. The XmlNodeReader needs an XmlNode as the source document;
typically this is an XmlDocument class. The overloaded constructors for the XmlValidatingReader
can accept a stream, string, or another XmlReader descendant as parameters.
After the XmlReader descendant instance has been constructed
you call the Read method to read in the first node. Then using one of the
many XmlReader properties you can access the details regarding that node, such
as NodeType, Name and Value. You can then continue to call the Read method
to loop through the entire document. When the Read method returns false you
have reached the end of the document.
|
The following uses an XmlTextReader to loop through a
specified file and add all the element names in the Xml document to a
ListBox.
|
|
Var
xr : XmlTextReader;
begin
xr := XmlTextReader.Create(txtFileName.Text);
while xr.Read Do
begin
if xr.NodeType = XmlNodeType.Element then
ListBox1.Items.Add(xr.Name);
end;
end;
|
|
The following uses an XmlTextReader to loop through a
specified file, adding the text values to the list box where the element name
is PHONE. Notice how you must call Read again to get the node that
contains the text value of the phone number.
|
|
Delphi for .NET
|
|
Var
xr : XmlTextReader;
begin
xr := XmlTextReader.Create(txtFileName.Text);
while xr.Read Do
begin
if (xr.NodeType = XmlNodeType.Element) and (xr.Name =
'PHONE') then
begin
if Not xr.Read then Break;
ListBox1.Items.Add(xr.Value);
end;
end;
|
The XmlValidatingReader provides an event named
ValidationEventHandler. This event is used to notify your application of a
validation error that may occur when looping through the document.
|
The following example demonstrates the use of the
ValidationEventHandler to validate the specified document.
|
|
/// Validation Event
procedure TMyWinForm.ValidationEvent(sender: Tobject;
args: ValidationEventArgs);
begin
isValid := False;
ValidErrorMsg := args.Message;
end;
// Button Click that opens document and validates it.
procedure TMyWinForm.ValidateBtn_Click(sender:
System.Object; e: System.EventArgs);
var
tr : XmlTextReader;
vr : XmlValidatingReader;
begin
// isValid is Declared in the Class, default to being
valid
isValid := True;
// Construct the XmlTextReader
tr := XmlTextReader.Create(txtFileName.Text);
// Construct the Validating Reader Passing the
XmlTextReader
vr := XmlValidatingReader.Create(tr);
// Attach Event Handler to be Notified if error occurs.
Include(vr.ValidationEventHandler,ValidationEvent);
// Read through all nodes of the file
while vr.Read do;
// Check if isValid was set to true in the event and what
message occurred.
if Not isValid then
MessageBox.Show(ValidErrorMsg)
else
MessageBox.Show('Document is Valid');
end;
|
Reading with
XmlDocument
The XmlDocument class implements the Xml DOM
specification. Since DOM is a W3C standardized API, much of the functionality
is similar between different implementations. When an XmlDocument is
constructed the entire Xml document is parsed and stored as a tree in
memory. This gives you bi-directional navigation, with the ability to make
changes to the XmlDocument in memory. Since the entire document is in memory
the class is not practical to use with large Xml documents.
After an XmlDocument is constructed you must call Load, or
LoadXML to specify the source document. The document source can be one of
many different things including a String, File, Stream, or XmlReader. No
Validating is done on the document, if you need the document validated you
should use an XmlValidatingReader to retrieve the source document. The
XmlDocument provides many methods to navigate and work with an Xml Document.
The .NET SDK Documentation is an excellent source of information on all of the
methods that are provided by the XmlDocument Class. This paper will attempt to
show how to use some of these methods.
The key class when dealing with an XmlDocument is an
XmlNode. An XmlNode can have any number of attributes and child XmlNodes. In
fact, XmlDocument is a descendant of XmlNode with a few additional methods and properties,
such as those used to read and write an Xml document.
The XmlNode Child Nodes can be accessed through the
following properties:
ChildNodes, FirstChild, LastNode, PreviousSibling, NextSibling.
The ChildNodes contain the array of all nodes which can be looped through,
using either a for loop or a while loop.
There are also two other key methods that allow you to
execute an XPath Statement and return a single node, or set of nodes:
SelectSingleNode and SelectNodes. These methods are very useful as they
prevent you from having to walk the document tree to get what you are after.
Instead, you can specify an XPath Query that will return the XmlNode(s) you are
after.
|
The following example uses a FOR loop (via Index) to
navigate all of the children of the root element adding their names to a
ListBox.
|
|
Var
XmlDoc : XmlDocument;
I : Integer;
RootNode : XmlNode;
begin
XmlDoc := XmlDocument.Create;
XmlDoc.Load(txtFileName.Text);
// Select the Root Node
RootNode := XmlDoc.SelectSingleNode('/*');
// Loop Through all of the Child Nodes of the Root and
Display their names
For I := 0 to RootNode.ChildNodes.Count -1 do
ListBox1.Items.Add(RootNode.ChildNodes.Item(I).Name);
end;
|
|
The following example uses a FOR loop (via Delphi 9 in Construct) to navigate all of the children of the root element adding their
names to a ListBox.
|
|
Var
XmlDoc : XmlDocument;
I : Integer;
RootNode : XmlNode;
ChildNode : XmlNode;
begin
XmlDoc := XmlDocument.Create;
XmlDoc.Load(txtFileName.Text);
// Select the Root Node
RootNode := XmlDoc.SelectSingleNode('/*');
// Loop Through all of the Child Nodes of the Root and
Display their names
For ChildNode in RootNode.ChildNodes do
ListBox1.Items.Add(ChildNode.Name);
end;
|
|
The following example uses a WHILE loop to navigate all of
the children of the root element, adding their names to a ListBox.
|
|
Var
XmlDoc : XmlDocument;
RootNode : XmlNode;
ChildNode : XmlNode;
begin
XmlDoc := XmlDocument.Create;
XmlDoc.Load(txtFileName.Text);
// Select the Root Node
RootNode := XmlDoc.SelectSingleNode('/*');
ChildNode := RootNode.FirstChild;
// Loop Through all of the Child Nodes of the Root and
Display their names
While Assigned(ChildNode) do
begin
ListBox1.Items.Add(ChildNode.Name);
ChildNode := ChildNode.NextSibling;
end;
end;
|
Reading with XmlDataDocument
The XmlDataDocument descends from XmlDocument and is enhanced
to load and save data to and from a Dataset. This can be a useful method to
data bind visual controls to an Xml Document.
In order to load an Xml Document with XmlDataDocument you
will need a schema that describes the Document. This document tells the
XmlDataDocument how to layout the tables and rows in the DataSet class.
First you must call the ReadXmlSchema method of the
XmlDataDocument Class to pass the schema of the document. Then you can call
Load to load the document desired.
Then you can use the DataSet Property to work with the Xml
Document as a DataSet, or you can work with XmlDataDocument just like you would
with XmlDocument.
The XPathNavigator class is one of my favorite methods for
reading Xml Documents. Used in combination with the XPathDocument Class, It
provides a fast and efficient way to query data stored in an Xml Document. The
only draw back to using XPathDocument is that it is read only. However, with
.NET 2.0 XPathDocument will add the ability to modify the document. Microsoft has
already started to recommend using XPathDocument over XmlDocument where
possible. If you are unfamiliar with XPath, I suggest you skip to the appendix
section on XPath found on Page 18.
The most important method on the XPathDocument class is CreateNavigator
which creates the XPathNavigator that allows you navigate the document. There
are many ways to use the XPath Navigator. In the Example below I show how to
use the Select method to create an XpathNodeIterator to loop through the
results of an XPath Query.
|
var
xNavDoc : XPathDocument;
xNav : XPathNavigator;
Nodes : XPathNodeIterator;
begin
xNavDoc :=
XPathDocument.Create('C:DEMOCLIENTLIST.XML');
xNav := xNavDoc.CreateNavigator;
Nodes := xNav.Select('/CLIENTLIST/CLIENT/PHONE');
while Nodes.MoveNext do
begin
ListBox1.Items.Add(Nodes.Current.Value);
end;
end;
|
There are many built-in ways to write an Xml Document, each
has its own benefits. Understanding these benefits and associated drawbacks,
will help you in determining which class is the correct one to use.
Some of the ways to write an Xml Document in the .NET
Framework
- The Abstract XmlWriter Class Descendant
- The XmlDocument Class and Descendants
- The WriteXml Method of DataSet
- Classes in System.Xml.Serialization Namespace
The XmlWriter is an abstract class. The framework provides
only one decendant the XmlTextWriter. The XmlWriter provides the basic
functionality required to create Xml. You can create both Xml documents and
document fragements using the XmlWriter. It is possible to create non-well
formed Xml Documents with XmlWriter so care must be taken to verify that your
output is well formed. The XmlWriter is a very fast and efficent method to
output Xml. For the most part, the other Framework classes that create Xml
are output through the XmlTextWriter. I personally find the XmlWriter to be
the easiest way to write Xml Documents.
|
Using an XmlWriter to produce the XML for an RSS feed.
|
|
Delphi for .NET
|
|
function TWinForm3.BasicRSSFeed: string;
var
XW : XmlTextWriter;
SW : StringWriter;
begin
SW := StringWriter.Create;
XW := XmlTextWriter.Create(SW);
XW.WriteStartDocument;
XW.WriteStartElement('rss');
XW.WriteAttributeString('version','2.0');
XW.WriteStartElement('channel');
XW.WriteElementString('title','Title of My Feed');
XW.WriteElementString('link','http://linktomyfeed/');
XW.WriteElementString('description','Description of my
Feed');
XW.WriteStartElement('item');
XW.WriteElementString('title','Item Title');
XW.WriteElementString('description','This is the
content');
XW.WriteElementString('pubdate',DateTime.Now.ToUniversalTime.ToString('r'));
XW.WriteEndElement; //item
XW.WriteEndElement; // channel
XW.WriteEndElement; // rss
XW.WriteEndDocument;
XW.Close;
SW.Close;
result := SW.ToString;
end;
|
XmlDocument can be used to write Xml Documents, as well as
read them.
|
<?xml version="1.0" encoding="utf-16"?>
<events>
<event name="BorCon">
<location>San Jose</location>
</event>
</events>
|
The following function demostrates how to create the above
document using XmlDocument.
|
function
CreateSampleDocument : String;
var
DOM : XmlDocument;
RootNode : XmlNode;
EventNode : XmlNode;
LocationNode : XmlNode;
AttrNode : XmlAttribute;
writer : StringWriter;
begin
DOM := XmlDocument.Create;
RootNode := DOM.CreateElement('events');
DOM.AppendChild(RootNode);
EventNode := DOM.CreateNode(XmlNodeType.Element,'event','');
AttrNode := DOM.CreateAttribute('name');
AttrNode.Value := 'BorCon';
EventNode.Attributes.Append(AttrNode);
LocationNode := DOM.CreateElement('location');
LocationNode.InnerText := 'San Jose';
EventNode.AppendChild(LocationNode);
RootNode.AppendChild(EventNode);
writer := StringWriter.Create;
DOM.Save(writer);
result := writer.ToString;
end;
|
One of the common problems you may
face in development is exporting relation data into a text based format, such
as XML. This can be accomplished using XmlDataDocument which
represents your relational data as an XmlDocument. The XmlDataDocument can then be
used as a source to an XSLT Transformation to produce the output document.
- Create a Dataset with the contents
from your Database.
- Create an XmlDataDocument passing the
DataSet that is filled with your database content.
- Create an XslTransform and Load the
XSLT document that will transform your dataset XML document into the
resulting feed format.
- Call Transform on the XslTranform
which will place your output into one of many formats. In the example
below I am using a StringWriter.
|
Var
XDD : XmlDataDocument;
SW : StringWriter;
XT : XslTransform;
DS : DataSet;
begin
BdpDataAdapter1.Fill(DS);
XDD := XmlDataDocument.Create(DS);
SW := StringWriter.Create();
XT := XslTransform.Create;
XT.Load('C:DEMOSTRANSFORM.XSL');
XT.Transform(XDD,nil,SW);
TextBox1.Text := SW.ToString;
end;
|
Serialization allows you to convert an object to a
persistent medium, such as a file. Then at any given time the object can be de-serialized
and loaded with values from the previously persistent state. One common
application of serialization is with web services, allowing your web methods to
return objects. The returning objects will be serialized as Xml, allowing them
to be transmitted over the wire.
The .Net Framework provides everything you need to serialize
an object in Xml Format.
There are some restrictions on Xml serialization.
- Only public properties and fields can be serialized.
- A class must have a default constructor to be serialized.
- Methods can not be serialized.
Serialization is handled through the XmlSerializer class. When
constructing an instance of the XmlSerializer you must pass the typeof the
class you wish to serialize.
Serialization is done with call to XmlSerializers Serialize
method, and De-serialization is done with a call to the Deserialize method.
|
Basic Serialization Example
|
|
Type
// Class to Serialize
CustomerClass = class(TObject)
public
FirstName : String;
LastName : String;
end;
procedure Serialize;
var
Customer : CustomerClass;
XS : XmlSerializer;
SW : StringWriter;
begin
// Create an instance of CustomerClass and populate it with
data
Customer := CustomerClass.Create;
Customer.FirstName := 'John';
Customer.LastName := 'Doe';
// Create an instance of XmlSerializer passing the
CustomerClass Type
XS := XmlSerializer.Create(TypeOf(CustomerClass));
// Create a TextWriter Decendant to store Serialized
Object
SW := StringWriter.Create;
// Serialize the Object to the TextWriter
XS.Serialize(SW,Customer);
// Show Serialized Object in a Message Box
MessageBox.Show(SW.ToString);
end;
|
|
Basic De-serialization Example
|
|
Type
// Class to Serialize
CustomerClass = class(TObject)
public
FirstName : String;
LastName : String;
end;
procedure DeSerialize(DocumentStr : String);
var
Customer : CustomerClass;
XS : XmlSerializer;
SR : StringReader;
begin
// Create an instance of XmlSerializer passing the
CustomerClass Type
XS := XmlSerializer.Create(TypeOf(CustomerClass));
// Create a TextReader or Stream Decendant and load the
serialized data into it.
SR := StringReader.Create(DocumentStr);
// Deserialize the TextReader/Stream Decendant and Type
Cast it to CustomerClass
Customer := CustomerClass(XS.Deserialize(SR));
// Display a Message Box to show Customer Information
MessageBox.Show(Customer.FirstName + ' ' + Customer.LastName);
end;
|
There are several different attributes that can be applied
to your class to control how it is serialized to Xml.
|
Example of Renaming the Xml Document Root Element and Sub
Element Names
|
|
[XmlRoot(ElementName = 'customer')]
CustomerClass = class(TObject)
public
[XmlElement(ElementName = 'FNAME')]
FirstName : String;
[XmlElement(ElementName = 'LNAME')]
LastName : String;
end;
|
|
Resulting File
|
|
<?xml version="1.0" encoding="utf-16"?>
<customer
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FNAME>John</FNAME>
<LNAME>Doe</LNAME>
</customer>
|
|
Example using XmlAttribute and Embeded Classes
|
|
[XmlRoot(ElementName = 'customer')]
CustomerClass = class(TObject)
public
type
NameClass = Class(TObject)
public
[XmlAttribute('First')]
FirstName : String;
[XmlAttribute('Last')]
LastName : String;
end;
public
[XmlElement('name')]
Name : NameClass;
end;
|
|
Resulting File
|
|
<?xml version="1.0"
encoding="utf-16"?>
<customer
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name First="John" Last="Doe"
/>
</customer>
|
The .Net Framework provides the necessary classes to perform
XSLT. The XslTranform class provides all of the functionality required. There
are two key methods that need to be called for every transformation. First you
must call XslTransform.Load to load the stylesheet that will be used in the
transformation. The second is XslTransform.Transform which will perform the transformation
on a specified Xml Source. Both methods are overloaded and have many
different signatures, please refer to the SDK Documentation for details on each
overload.
|
Var
XDD : XmlDataDocument;
SW : StringWriter;
XT : XslTransform;
DS : DataSet;
begin
BdpDataAdapter1.Fill(DS);
XDD := XmlDataDocument.Create(DS);
SW := StringWriter.Create();
XT := XslTransform.Create;
// Load The transformation
XT.Load('C:DEMOSTRANSFORM.XSL');
// Perform Transformation
XT.Transform(XDD,nil,SW);
TextBox1.Text := SW.ToString;
end;
|
The .Net framework provides a command line utility (XSD.EXE)
that is very useful for dealing with serialization and schemas.
XSD.EXE The Xml Schema Definition Tool
The XSD tool can do the following
7
Generating Schema Documents, from one or more Xml Instance
Documents
7
Creating a Serialized Class from a Schema
7
Creating a typed DataSet Class from a Schema
7
Convert a Compiled Serialized Class in an Assembly in to XSD
Petr Vones a repected member of the Delphi Community has
created a Delphi open tool that wraps the functionality found in XSD. The
Open Tool also contains several other useful XML Tools. This tool makes it
easy to create Delphi versions of the Classes.
This tool can be downloaded here:
http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=21094
The following is the Xml Document that is used in the
examples found in the Appendix.
|
Training.xml
|
|
<?xml version=1.0 encoding=ISO-8859-1
standalone=yes?>
<training>
<class>
<name number=401> Introduction to
XML</name>
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<presenter>Robert Love</presenter>
<event name=BorCon/>
</class>
<class>
<name number=402> Introduction to
.NET</name>
<subject>Borland will really show you how to do
.NET</subject>
<presenter>Al Borland</presenter>
<event name=BorCon/>
</class>
</training>
|
XPath is a syntax used to query an XML document tree.
XPath gets its name due to the path notation that it uses to describe the XML
tree. XPath is a critical stepping-stone if you desire to learn XSLT. It also
provides a quick way you can query an XML document and get either a node set,
or a single value result.
XPath uses a path like syntax. The path delimiter is /"
like you would find in a Linux based system. Each node in the tree can be
compared to a directory on your file system. Most of the examples in this
section will be using the original training.xml document. The results of each
query will display the raw XML of each of the nodes returned.
|
Say we want to get a list of presenters in our document.
We can access that list by specifying the path to the presenter.
|
|
Query
|
|
|
/training/class/presenter
|
|
Result
|
|
|
<presenter>Robert Love</presenter>
<presenter>Al Borland</presenter>
|
|
Stepping back one level and returning a list of classes
will not just return the class but all child elements.
|
|
Query
|
|
|
/training/class
|
|
Result
|
|
|
<class>
<name number="401">Introduction
to XML</name>
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<presenter>Robert Love</presenter>
<event name="BorCon"/>
</class>
<class>
<name
number="402">Introduction to .NET</name>
<subject>Borland will really show you
how to do .NET</subject>
<presenter>Al Borland</presenter>
<event name="BorCon"/>
</class>
|
Currently all Xpath statements we have explored have started
with a single / this is considered an absolute path. If you start directly
with a name such as training/class/subject it is applied to a current context
node. In all of the prior examples the context has been the implied document
node. When we introduce XPath predicates and XSLT you will see practical use
of relative paths.
You also have an option that allows you to search for nodes
with-in a document. Using // you can search for all nodes, regardless of
location, that match the following.
|
If you want to see all of the nodes with name of subject
this could be done with.
|
|
Query
|
|
|
//subject
|
|
Result
|
|
|
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<subject>Borland will really show you how to do
.NET</subject>
|
You can also use * as a wildcard inside of your path.
|
The following example uses the wild card twice. It will
return all subject nodes that are in the 3rd tree level.
|
|
Query
|
|
|
/*/*/subject
|
|
Result
|
|
|
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<subject>Borland will really show you how to do
.NET</subject>
|
Just like paths you can use . and .. to represent the
current and prior nodes.
|
The following example shows how to use . to get the
current node.
Although this example is not very practical, it is only
meant to introduce you to the fact that . can be used.
|
|
Query
|
|
|
/training/*/.
|
|
Result
|
|
|
<class>
<name
number="401">Introduction to XML</name>
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<presenter>Robert Love</presenter>
<event name="BorCon"/>
</class>
<class>
<name number="402">Introduction
to .NET</name>
<subject>Borland will really show you
how to do .NET</subject>
<presenter>Al Borland</presenter>
<event name="BorCon"/>
</class>
|
|
The following example shows how to use .. to get the
previous node.
Although this example is not very practical, it is only
meant to introduce you to the fact that .. can be used.
|
|
Query
|
|
|
/training/*/..
|
|
Result
|
|
|
<training>
<class>
<name
number="401">Introduction to XML</name>
<subject>XML, DTD, XSD, DOM,
XPATH, and XSLT.</subject>
<presenter>Robert
Love</presenter>
<event
name="BorCon"/>
</class>
<class>
<name
number="402">Introduction to .NET</name>
<subject>Borland will really
show you how to do .NET</subject>
<presenter>Al
Borland</presenter>
<event
name="BorCon"/>
</class>
</training>
|
Current and Prior nodes can also be obtained through an axis
type statement. An axis allows you to specify what the current node will
query. To specify an axis, the location path is prefixed with the axis.
This can be done with the following syntax:
axis::path
Following shows two ways to get current and prior nodes.
|
Axis Syntax
|
. and .. Syntax
|
|
/training/*/self::*
|
/training/*/.
|
|
/training/*/parent::*
|
/training/*/..
|
So basically . is a shortcut for the self axis, and ..
is a shortcut for the parent axis.
There are several other axes that you can use in an XPath
statement.
|
Axis
|
Description
Many descriptions taken
directly from the XPath Specification
|
|
Self
|
Identifies the context node.
|
|
Child
|
Contains the children of the context node
This is the default axis. If you dont specify an axis
child is implied.
|
|
Parent
|
Contains the parent of the context node if there is one.
|
|
descendant
|
Contains the descendants of
the context node; a descendant is a child or a child of a child and so on;
thus the descendant axis never contains attribute or namespace nodes.
|
|
descendant-or-self
|
Contains the
context node and the descendants of the context node.
|
|
Ancestor
|
Contains the ancestors of the
context node; the ancestors of the context node consist of the parent of
context node and the parent's parent and so on; thus, the ancestor axis will
always include the root node, unless the context node is the root node.
|
|
Ancestor-or-self
|
Contains all nodes in the same
document as the context node that are after the context node in document
order, excluding any descendants and excluding attribute nodes and namespace
nodes.
|
|
following
|
Contains all nodes in the same
document as the context node that are after the context node in document
order, excluding any descendants and excluding attribute nodes and namespace
nodes.
|
|
following-sibling
|
Contains all the following
siblings of the context node; if the context node is an attribute node or
namespace node.
|
|
preceding
|
Contains all nodes in the same
document as the context node that are before the context node in document
order, excluding any ancestors and excluding attribute nodes and namespace
nodes.
|
|
preceding-sibling
|
Contains all the preceding
siblings of the context node; if the context node is an attribute node or
namespace node, the preceding-sibling axis is empty.
|
|
attribute
|
Contains the attributes of the
context node; the axis will be empty unless the context node is an element.
|
|
namespace
|
Contains the namespace nodes
of the context node; the axis will be empty unless the context node is an
element.
|
The path statement will only take you so far. Sometimes you
need to select which part of the list you are looking for. Using the [] you
can include a statement to limit the result set, this is called Predicate.
|
In the query below we look at the presenter name and only
return the class that matches that presenters name.
|
|
Query
|
|
|
/training/class[presenter="Robert Love"]
|
|
Result
|
|
|
<class>
<name number="401">Introduction
to XML</name>
<subject>XML, DTD, XSD, DOM, XPATH, and
XSLT.</subject>
<presenter>Robert Love</presenter>
<event name="BorCon"/>
</class>
|
|
To access an attribute you must prefixing its name with a
@.
In the following example, we are requesting a list of
classes where number attribute is the value of 402.
|
|
Query
|
|