Working with the xml Data Type in Visual Studio Client Applications
The xml data type in SQL Server 2005 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 2005 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 in SQL Server 2005. 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;
See Also
Other Resources
XQuery Against the xml Data Type
Writing Client Applications