Converting rootless XmlReader to XmlDocument in .NET

by Armand Niculescu Email
  • Currently 2.81/5
  • 1
  • 2
  • 3
  • 4
  • 5
  • i

MS SQL has the ability to retrieve data as XML by using the "FOR XML [RAW | AUTO [ELEMENTS] | EXPLICIT]" parameters, which is very useful especially when used in a web service that communicates with a Flash / Flex client as the results don't have to be converted, but just output to the client.

Your code might look something like this:

C#:

public static XmlDocument ExecuteSelectXmlCmd(string sQuery, bool nodes)
{
        if (sQuery.ToLower().IndexOf("for xml") < 0)
        {
                sQuery += " FOR XML AUTO";
                if (nodes == true)
                        sQuery += ", ELEMENTS";
        }
       
        string sConn = ConfigurationManager.AppSettings["ConnectionString"] /* get the connection string from web.config */
        SqlConnection oConn = new SqlConnection(sConn);
        try
        {
                oConn.Open();
        }
        catch { throw new Exception(sConn); }
        if (oConn.State != ConnectionState.Open)
                throw new Exception("Connection unavailable");
               
        SqlCommand cmd = new SqlCommand();
       
        // this can be a security issue!
        cmd.CommandText = sQuery;
       
        cmd.Connection = oConn;
       
        cmd.CommandType = CommandType.Text;
        XmlReader xmlRead = cmd.ExecuteXmlReader();
        oConn.Close();
}

Besides the possible security issues (it'd be much better to use parametrized queries), there's a problem with this code: it returns an XmlReader without a root node, so you can't return that to your client.

Follow up:

There's no straightforward way to convert a XmlReader that does not have a root element to a XmlDocument - most of the code samples I've seen simply read sequentially through the XmlReader, appending data to a string. Obviously this is inneficient from a performance standpoint.

The better way to handle this is via a rather obscure method, mentioned on MSDN:

It involves using an XPathNavigator, like this:

XPathDocument xp = new XPathDocument(xmlRead);
XPathNavigator xn = xp.CreateNavigator();

so you end up with an XmlNode.

Then you can create the XmlDocument like usual, with a root node

XmlDocument xd = new XmlDocument();
XmlNode root = xd.CreateElement("root");

and dump the node inside:

root.InnerXml = xn.OuterXml;
xd.AppendChild(root);

So the whole method might look like this:

C#:

public static XmlDocument ExecuteSelectXmlCmd(string sQuery, string sRootName, bool nodes)
{
        if (sQuery.ToLower().IndexOf("for xml") < 0)
        {
                sQuery += " FOR XML AUTO";
                if (nodes == true)
                        sQuery += ", ELEMENTS";
        }
        string sConn = ConfigurationManager.AppSettings["ConnectionString"] /* get the connection string from web.config */
        SqlConnection oConn = new SqlConnection(sConn);
        try
        {
                oConn.Open();
        }
        catch { throw new Exception(sConn); }
        if (oConn.State != ConnectionState.Open)
                throw new Exception(&quot;Connection unavailable&quot;);
               
        SqlCommand cmd = new SqlCommand();
        // this can be a security issue!
        cmd.CommandText = sQuery;
        cmd.Connection = oConn;
        cmd.CommandType = CommandType.Text;
        XmlReader xmlRead = cmd.ExecuteXmlReader();

        XPathDocument xp = new XPathDocument(xmlRead);
        XPathNavigator xn = xp.CreateNavigator();
        XmlDocument xd = new XmlDocument();
        XmlNode root = xd.CreateElement(sRootName);
        root.InnerXml = xn.OuterXml;
        xd.AppendChild(root);
        oConn.Close();
        return xd;
}

SQLXML

If you don't want to add the root tag by yourself or if you need to apply a XSL transformation on the returned XML, you can use SQLXML. In case you don't have it installed, you can download it from Microsoft and install it; then you can add it as reference in your project.

To use it, add this in your class:

using Microsoft.Data.SqlXml;

then, modify the query part of the method like this:

C#:

string sConn = ConfigurationManager.AppSettings["ConnectionString"];
SqlXmlCommand cmd = new SqlXmlCommand(sConn);
cmd.RootTag = sRootName;
cmd.CommandText = sQuery;
XmlReader xmlRead = cmd.ExecuteXmlReader;
XmlDocument xd = new XmlDocument();
xd.Load(xmlRead);
oConn.Close();
return xd;

The rest stays the same.

Futher reading

5 comments

Comment from: József Andros [Visitor] Email
To quote you "There's no straightforward way to convert a XmlReader to a XmlDocument - most of the code samples I've seen simply read sequentially through the XmlReader, appending data to a string. Obviously this is inneficient.".

Isn't much easier to use the "Load" method on the XmlDocument class? One of the 4 overloads accept an XmlReader as aparameter.

12 Feb 07 @ 17:29
Comment from: Armand Niculescu [Member] Email · http://www.media-division.com
There was some poor wording on my part.
It should have read "There's no straightforward way to convert a XmlReader without a root node to a XmlDocument".
15 Feb 07 @ 12:16
Comment from: sam sinfield [Visitor] Email · http://www.samsinfield.net
This looked to be exactly what I needed for converting data from an sql server db to a xmldoc. Unfortunately, I'm using .net 1.1 and don't have the option to upgrade and this has only been added in .net 2.0. Is there any other, elegant way of doing this in 1.1 without having to sequentially read through the XmlReader
21 May 07 @ 14:28
Comment from: Armand Niculescu [Member] Email · http://www.media-division.com
Sam, if you're using MSSQL 2005, you can specify the root node in the query itself, like this:
...FOR XML AUTO, ROOT('doc')

I don't know of any other way.

21 May 07 @ 17:48
Comment from: Wayne Scholar [Visitor] Email · http://www.getabby.com
Great Article. We're using Flex and needed this badly!

Thanks!

Wayne
06 Jun 07 @ 15:32

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
This is a captcha-picture. It is used to prevent mass-access by robots.
Please enter the characters from the image above. (case insensitive)

This is the blog of the Media Division team. We're giving back to the community some of the things we have learned while building all sorts of apps. Concentrating on Flash/Actionscript, we'll also cover C#, MSSQL, ColdFusion/Oracle and areas like Photography and design. We're writing original articles only - no silly stuff to generate more traffic.

Search

XML Feeds

Aggregated by MXNA

Aggregated by MXNA

Related Links