Working with the xml Data Type in Visual Studio Client Applications

This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.

The xml data type lets you store XML fragments, such as an XML instance missing a single top-level element, and valid XML documents in a SQL Server database. Because of this design characteristic, the xml data type instances must be mapped in Visual Studio 2005 to an array of System.Xml.XmlNode instead of returned as System.Xml.XmlDocument. This does not support fragmented XML.

In working directly with the array of XmlNode that is contained by the xml data type instance value, you will notice differences between the ways the InnerXml and OuterXml member properties work, especially in the case where the xml data type instance forms a valid XML document, such as it has a single top-level element.

For example, suppose you have the following lines of code that initiate a new instance of a SQL Server endpoint (MyServer.sql_endpoint) as a Web proxy that has a Web method (GetSomeXml) that returns an xml data type row instance value:

MyServer.sql_endpoint proxy = new MyServer.sql_endpoint();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
SqlXmlDt = proxy.MyServerdboGetSomeXml();
System.Xml.XmlNode[] nodeArr = SqlXmlDt.Any;
string xmlJustChildren = nodeArr[0].InnerXml;
string xmlWithRoot = nodeArr[0].OuterXml;

The xml data type row value returned then has the following data:

<root><child/><child/></root>

If the InnerXml and OuterXml properties for nodeArr[0] are then assigned out to a pair of string variables (xmlJustChildren and xmlWithRoot), as shown in the previous code, the value of nodeArr[0].InnerXml includes only nodes that are contained within the current element (both <child/> elements but not the <root> element itself), and nodeArr[0].OuterXml works as expected: including all nodes in the array of XmlNodes (the <child/> elements and also the <root> element).

Note that this behavior differs from what you might typically see if you work more frequently with XmlDocument because that class implements the InnerXml and OuterXml properties differently. For XmlDocument instances, the document instance acts as wrapper elements to all the XmlNodes in the document. This includes the top-level root node and any inline DTDs or schemas you might have in the document. Therefore, the contents of XmlDocument.InnerXml is the same as XmlDocument.OuterXml.

Because of these implementation specifics, using System.Xml.XmlDocumentFragment is a good alternative for working with SQL Server xml data type instances in client applications that work with Native XML Web Service. The XmlDocumentFragment class will be more familiar to developers who are used to using XmlDocument, and XmlDocumentFragment accepts an array of XmlNode without issue.

The following sections provide code and overview of how to use the XmlDocumentFragment to work with SQL Server xml data type instance values in client applications.

Processing Output by Using XmlDocumentFragment

The following lines of code show how to put an array of XmlNode into an XmlDocumentFragment, and then select nodes from the fragment by using an XPath expression.

System.Xml.XmlDocumentFragment fragOut = SqlXmlDt.Any[0].OwnerDocument.CreateDocumentFragment();

//  Loop over your XmlNode array and populate your XmlDocumentFragment.
foreach (System.Xml.XmlNode xmlnode in SqlXmlDt.Any)
{
    fragOut.AppendChild(xmlnode);
}

//  Loop over your XPath expression/selection for results.
foreach (System.Xml.XmlNode xmlpath in fragOut.SelectNodes("//bar"))
{
    System.Console.WriteLine(xmlpath.OuterXml);
}

Building Input with a String by Using XmlDocumentFragment

The following demonstrates how to build an input array of XmlNode by using a string assignment to the InnerXml property of XmlDocumentFragment.

//  Create an owning XmlDocument
System.Xml.XmlDocument xmldoc = new System.Xml.XmlDocument();

//  Create your XmlDocumentFragment.
System.Xml.XmlDocumentFragment fragIn = xmldoc.CreateDocumentFragment();

//  Fill the XmlDocumentFragment with a string.
fragIn.InnerXml =
"  <a>" +
"    <b>inputvalue</b>" +
"  </a>" +
"  topstuff" +
"  <b/>";

//  Create an XmlNode array (should never require more than one element).
System.Xml.XmlNode[] xmlnodes = new System.Xml.XmlNode[1];

//  Put the XmlDocumentFragment in the array and fill your XmlDt
xmlnodes[0] = (System.Xml.XmlNode) fragIn;
SqlXmlDt.Any = xmlnodes;

Building Input from a File by Using XmlDocumentFragment

The XmlDocumentFragment class is more limited than the XmlDocument class when it comes to how to populating an instance. The following example shows how to populate an XmlDocumentFragment instance from a file by using System.Xml.XmlReader.

//  Create an owning XmlDocument.
System.Xml.XmlDocument xmldoc = new System.Xml.XmlDocument();

//  Create your XmlDocumentFragment.
System.Xml.XmlDocumentFragment fragIn = xmldoc.CreateDocumentFragment();

//  Build an XmlReader from the file.
System.Xml.XmlReaderSettings rs = new System.Xml.XmlReaderSettings();
rs.ConformanceLevel = System.Xml.ConformanceLevel.Fragment;
System.Xml.XmlReader reader = System.Xml.XmlReader.Create("c:\\file.xml", rs);

//  Populate the fragment with the nodes from the XmlReader.
System.Xml.XmlNode child;
while (null != (child = xmldoc.ReadNode(reader)))
     fragIn.AppendChild(child);

//  Create your XmlNode array (should never require more than one element)
    System.Xml.XmlNode[] xmlnodes = new System.Xml.XmlNode[1];

//  Put the XmlDocumentFragment in the array and fill our XmlDt.
xmlnodes[0] = (System.Xml.XmlNode) fragIn;
SqlXmlDt.Any = xmlnodes;