Using Non-Canonical XPaths in Message Assignments
If you use .Net message parts, it is possible to annotate your code with the XML serialization attribute that, when also accompanied by distinguished fields and/or property annotations, can result in fairly complex XPath expressions. It is possible that these complex XPath expressions will be non-canonical. Non-canonical XPath should only be used in direct bound orchestrations and may fail with logically or physically bound orchestrations. Direct bound orchestrations do not rely on a pipeline for processing the XML document; as a result, the entire XML document is loaded in memory prior to processing.
Canonical and Non-Canonical XPath
The canonical or short-form of XPath uses the abbreviated syntax from the XPath specification (http://www.w3.org/TR/xpath) to specify a location path. Some distinguishing properties of canonical XPath expressions include:
The
child::
axis is assumed by default for each step of the expression@
is short forattribute::
.//
is short for/descendant-or-self::node()/
..
is short forself::node()
...
is short forparent::node()
.Canonical XPath expressions are simple expressions such as
/*[local-name()='element-name' and namespaceURI()='http://MyUri.org']/*[local-name()='element-name']/@*[local-name='attribute-name']
.This can be contrasted with the non-canonical form of XPath. This form is also known as the "general form" or "arbitrary XPath" and is distinguished by expressions that are arbitrarily complex and may combine multiple axes:
//element-name//*[local-name()='element-name' and position()=2]
.
Example
Consider the following program:
using System;
using System.IO;
using System.Xml.Serialization;
using Microsoft.XLANGs.BaseTypes;
namespace ComplexNetXPath
{
public class Animal
{
[Property( typeof(BTS.RetryCount) )]
public int NumberOfLegs;
}
public class Snake : Animal
{
public Snake()
{
NumberOfLegs = 0;
}
}
public class Dog : Animal
{
public Dog()
{
NumberOfLegs = 4;
}
}
public class Zoo
{
//
// Dogs and snakes are the possible animals of
// the week.
//
[XmlElement(typeof(Snake))]
[XmlElement(typeof(Dog))]
public Animal AnimalOfTheWeek;
}
class Class1
{
static void Main(string[] args)
{
XmlSerializer ser = new XmlSerializer(typeof(Zoo));
Stream s = Console.OpenStandardOutput();
Zoo z = new Zoo();
z.AnimalOfTheWeek = new Dog();
ser.Serialize( s, z );
s.Flush();
Console.WriteLine("------------------");
z.AnimalOfTheWeek = new Snake();
ser.Serialize( s, z );
s.Flush();
}
}
}
The Zoo type contains an Animal field that may be either a Snake or a Dog. The Animal instance has a NumberOfLegs field that is annotated with the PropertyAttribute which assigns the BTS.RetryCount property to this field.
Note
A real application would define its own properties.
When the animal of the week is a dog, the serialized Zoo instance looks like this:
<Zoo>
<Dog>
<NumberOfLegs>4</NumberOfLegs>
</Dog>
</Zoo>
When the animal of the week is a snake, the serialized Zoo instance looks like this:
<Zoo>
<Snake>
<NumberOfLegs>0</NumberOfLegs>
</Snake>
</Zoo>
Considering the Xml schema equivalent to the .Net Zoo class, the XPath expression for selecting the RetryCount property would allow for either a Snake or a Dog step to appear on the path to the property:
/*[local-name()='Zoo' and namespace-uri()='']/*[(local-name()='Dog' and namespace-uri()='') or (local-name()='Snake' and namespace-uri()='')]/*[local-name()='NumberOfLegs' and namespace-uri()='']
The XML pipeline components cannot handle this non-canonical XPath expression. To avoid this situation, multiple-choice Xml serialization attributes should not be used in conjunction with the XML pipelines and care should be taken when using the following xml serialization attributes:
XmlElementAttribute
XmlAttributeAttribute
XmlArrayItemAttribute