Is there an efficient way to turn LINQ-to-SQL data into XML?

I am looking at creating a template for my site. I am using ASP.NET MVC and Linq-to-SQL.

So,

What I want to do is create an XML document like this :

<?xml version="1.0" encoding="utf-8" ?>
<MainPage>
  <MainPageHtml><![CDATA[<p>lol!</p><br/>wtf? totally!]]></MainPageHtml>
  <Roles>
    <Role RoleId="1">User</Role>
    <Role RoleId="2">Administrator</Role>
  </Roles>
</MainPage>

      

And transform it with XSLT like this ::

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no" encoding="iso8859-1" omit-xml-declaration="yes"/><xsl:template match="/">
  <xsl:value-of select="/MainPage/MainPageHtml"/>
  <![CDATA[<select>]]><xsl:for-each select="//Roles/Role">
    <![CDATA[<option value="]]><xsl:value-of select="@RoleId"/><![CDATA[">]]><xsl:value-of select="."/><![CDATA[</option>]]></xsl:for-each>
  <![CDATA[</select>]]></xsl:template>
</xsl:stylesheet>

      

Using this kind of code :

XmlDocument data = new XmlDocument(); data.Load("Data.xml");

XslCompiledTransform transform = new XslCompiledTransform(); transform.Load("Transform.xslt");

StringWriter sw = new StringWriter();
transform.Transform(data, null, sw);
Console.WriteLine(sw.ToString());

Console.ReadKey(true);

      

Is there a quick way to transform a Linq based model like this:

return View("MainPage", new MainPageModel
{
    MainPageHtml = Config.MainPageHtml,
    Roles = Config.GetAllRoles()
});

      

In the above model?

+2


source to share


2 answers


Well, I found this method:

        var roles = from r in db.Roles
                    orderby r.Name
                    select new XElement("Role",
                        new XAttribute("RoleId", r.RoleID),
                        r.Name);

        var data = new XElement("MainPage", 
                        new XElement("Roles", roles));

        return View(data);

      

This makes it pretty easy to create. Anything better?

EDIT: I wrote XSLT View Engine



Here's almost my entire solution:

public class XsltViewEngine : VirtualPathProviderViewEngine
{
    public XsltViewEngine()
    {
        base.ViewLocationFormats = new string[]
        {
            "~/Views/{1}/{0}.xslt",
            "~/Views/Shared/{0}.xslt",
        };

        base.PartialViewLocationFormats = base.ViewLocationFormats;
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        return new XsltViewPage(partialPath);
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        return new XsltViewPage(viewPath);
    }
}

class XsltViewPage : IView
{
    protected string ViewPath { get; private set; }

    public XsltViewPage(string viewPath)
    {
        this.ViewPath = viewPath;
    }

    public void Render(ViewContext viewContext, TextWriter writer)
    {
        XslCompiledTransform transform = new XslCompiledTransform();
        transform.Load(viewContext.HttpContext.Server.MapPath(this.ViewPath));

        object model = viewContext.ViewData.Model;

        if (model == null)
        {
            throw new InvalidOperationException("An attempt was made to render an XSL view with a null model.  This is invalid.  An XSL view model must, at very least, be an empty XML document.");
        }

        if(model is IXPathNavigable)
        {
            transform.Transform((IXPathNavigable)model, null, writer);
        }
        else if (model is XNode)
        {
            transform.Transform(((XNode)model).CreateReader(), null, writer);
        }
        else
        {
            throw new InvalidOperationException("An attempt was made to render an XSL view with an invalid model.  An XSL view model must be either an IXPathNavigable or an XNode.");
        }
    }
}

      

And in Globals.asaxcs:

    protected void Application_Start()
    {
        ViewEngines.Engines.Add(new XsltViewEngine());

        RegisterRoutes(RouteTable.Routes);
    }

      

+1


source


I doubt there is an easy way to do what you need.

What I am doing for a similar situation is to add a ToXML () method to my data classes (newlines are not needed, but help when printing XML for diagnostic purposes, so I always insert them).

public string ToXML() {
    string xml =
        " <provider>" + m_newLine +
        "   <id>" + m_id + "</id>" + m_newLine +
        "   <providerid>" + m_providerId + "</providerid>" + m_newLine +
        "   <providername>" + ProviderName + "</providername>" + m_newLine +
        " </provider>";
    return xml;
}

      

This apporach won't do all the work for you, but it will lead you on your way.

Roles = Config.GetAllRoles(); 
string rolesXML = "<MainPage><MainPageHtml><p>lol!</p><br/>wtf? totally!></MainPageHtml>  <Roles>"
Roles.ForEach(r => rolesXML += String.Format("<Role RoleId='{0}'>{1}</Role>", r.ID, r.Description));
string rolesXML += "</Roles>";

      



In your XSL, you don't need CDATA sections for new elements. Instead:

<![CDATA[<option value="]]><xsl:value-of select="@RoleId"/><![CDATA[">]]><xsl:value-of select="."/><![CDATA[</option>]]>

      

you can use much clearer:

<option>
    <xsl:attribute name="value"><xsl:value-of select="@RoleId"/></xsl:attribute>
    <xsl:value-of select="."/>
</option>

      

+1


source







All Articles