我正在为我的网站构建一个模板引擎。我正在使用ASP.NET MVC和Linq-to-SQL。
所以,
我想要做的是生成这样的XML文档:
<?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>
使用XSLT将其转换为:
<?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>
使用此类代码:
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);
有没有一种快速方法可以像这样转变基于Linq的模型:
return View("MainPage", new MainPageModel
{
MainPageHtml = Config.MainPageHtml,
Roles = Config.GetAllRoles()
});
进入上面的模型?
答案 0 :(得分:1)
我怀疑有一种简单的方法来做你想要的事情。
我为类似情况所做的是在我的数据类中添加一个ToXML()方法(新行不是必需的,但在打印XML用于诊断目的时有帮助,所以我总是把它们放进去。)
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;
}
那个apporach不会为你完成整个工作,但会让你走上正轨。
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>";
在您的XSL中,您不需要新元素的CDATA部分。而不是:
<![CDATA[<option value="]]><xsl:value-of select="@RoleId"/><![CDATA[">]]><xsl:value-of select="."/><![CDATA[</option>]]>
你可以使用更清晰的东西:
<option>
<xsl:attribute name="value"><xsl:value-of select="@RoleId"/></xsl:attribute>
<xsl:value-of select="."/>
</option>
答案 1 :(得分:1)
好吧,我找到了这个方法:
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);
这样可以轻松创建。还有什么更好的吗?
编辑:我写了一个XSLT视图引擎
这几乎是我的整个解决方案:
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's 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's model must be either an IXPathNavigable or an XNode.");
}
}
}
而且,在Globals.asaxcs:
protected void Application_Start()
{
ViewEngines.Engines.Add(new XsltViewEngine());
RegisterRoutes(RouteTable.Routes);
}