可以将 XSLT 样式表添加到序列化的 XML 文档吗?
Posted
技术标签:
【中文标题】可以将 XSLT 样式表添加到序列化的 XML 文档吗?【英文标题】:Possible to add a XSLT Stylesheet to a serialized XML document? 【发布时间】:2021-06-16 15:52:56 【问题描述】:我有将复杂对象序列化为 XML 并将其保存为文件的代码,有没有一种快速的方法可以在序列化过程中在 xml 中包含样式表?
使用 C# 和 .net 框架 v2。
【问题讨论】:
【参考方案1】:您可以使用XmlWriter
和WriteProcessingInstruction
:
XmlSerializer s = new XmlSerializer(typeof(myObj));
using (XmlWriter w = XmlWriter.Create(@"c:\test.xml"))
w.WriteProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"USED-FILE.xsl\"");
s.Serialize(w, myObj);
【讨论】:
在我的解决方案中,它全部写在一行上。我可以调整以在多行上写吗? 对于懒惰的人,XmlSerializer
在System.Xml.Serialization
命名空间中。【参考方案2】:
对于那些想知道如何在现代 dotnet 核心中实现类似功能的人,您需要进行一些调整:
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
namespace ContentNegotiation
public class Program
public static void Main(string[] args) => CreateWebHostBuilder(args).Build().Run();
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
public class MyXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
// TODO: add me only if controller has some kind of custom attribute with XSLT file name
xmlWriter.WriteProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"template.xsl\"");
base.Serialize(xmlSerializer, xmlWriter, value);
public class Startup
public void ConfigureServices(IServiceCollection services)
services.AddMvc(options =>
options.RespectBrowserAcceptHeader = true; // default is false
// options.OutputFormatters.Add(new XmlSerializerOutputFormatter()); // not enough
options.OutputFormatters.Add(new MyXmlSerializerOutputFormatter());
)
// .AddXmlSerializerFormatters() // does not added by default, but not enough
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseStaticFiles();
app.UseMvc();
public class Post
public int Id get; set;
public string Title get; set;
public string Body get; set;
[ApiController]
public class DemoController : ControllerBase
// curl -k -i -s -H 'Accept: text/xml' http://localhost:5000/posts
// curl -k -i -s -H 'Accept: application/json' http://localhost:5000/posts
[HttpGet]
[Route(nameof(Posts))]
public IEnumerable<Post> Posts() => new[]
new Post
Id = 1,
Title = "Hello World",
Body = "Lorem ipsum dot color"
,
new Post
Id = 2,
Title = "Post 2",
Body = "Lorem ipsum dot color"
;
我们正在 ConfigureServices 中打开内容协商,并提供 XmlSerializerOutputFormatter 的实现,它将 XSL 添加到输出中
所以现在我们的后端将使用 JSON 响应如下请求:
curl -k -i -s -H 'Accept: application/json' http://localhost:5000/posts
和 XML:
curl -k -i -s -H 'Accept: text/xml' http://localhost:5000/posts
可在此处找到用于演示的 xsl 示例:https://mac-blog.org.ua/dotnet-content-negotiation/
【讨论】:
【参考方案3】:我写这个是为了减少问题,只在类上添加一个属性,就像我们描述每个其他 xml 构造指令一样:
用法是:
[XmlStylesheet("USED-FILE.xsl")]
public class Xxx
// etc
Xxx x = new Xxx();
XmlSerializer s = new XmlSerializer(typeof(Xxx));
using (var tw = File.CreateText(@"c:\Temp\test.xml"))
using (var xw = XmlWriter.Create(tw))
s.SerializeWithStyle(xw, x); // only line here that needs to change.
// rest is standard biolerplate.
为此所需的库代码:(保持在同一个命名空间中,因此当 IntelliSense 为属性添加命名空间时,它也会拉入扩展方法)
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using System.Reflection;
using System.Xml;
namespace NovelTheory.Xml.Serialization
public class XmlStylesheetAttribute : Attribute
public string Href get; set;
public XmlStylesheetAttribute(string href)
Href = href;
public static class XmlStylesheetAttributeExtenstions
public static void SerializeWithStyle(this XmlSerializer serializer,
XmlWriter textWriter, object o)
AddStyleSheet(textWriter, o);
serializer.Serialize(textWriter, o);
public static void SerializeWithStyle(this XmlSerializer serializer,
XmlWriter textWriter, object o, XmlSerializerNamespaces namespaces)
AddStyleSheet(textWriter, o);
serializer.Serialize(textWriter, o, namespaces);
private static void AddStyleSheet(XmlWriter textWriter, object o)
var dnAttribute = o.GetType()
.GetTypeInfo()
.GetCustomAttribute<XmlStylesheetAttribute>();
if (dnAttribute != null)
textWriter.WriteProcessingInstruction("xml-stylesheet",
$@"type=""text/xsl"" href=""dnAttribute.Href""");
【讨论】:
【参考方案4】:createXML.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='gss.xsl'");
#region // PAGES
string pages_xmlurl = Server.MapPath(Url.Content("~/xml/pages_" + lng.code + ".xml")).ToString();
XmlTextWriter pages_XML = new XmlTextWriter(pages_xmlurl, UTF8Encoding.UTF8);
pages_XML.WriteStartDocument();
pages_XML.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='gss.xsl'");
pages_XML.WriteComment("Generator By OS sitemap generator, http://www.oguzhansari.com");
pages_XML.WriteStartElement("urlset");
pages_XML.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
pages_XML.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
pages_XML.WriteAttributeString("xsi:schemaLocation", "http://www.google.com/schemas/sitemap/0.84");
pages_XML.WriteEndDocument();
pages_XML.Close();
XmlDocument pages_XMLCONTENTS = new XmlDocument();
pages_XMLCONTENTS.Load(pages_xmlurl);
var pages = db.pages.Where(w => w.isActive == true & w.isDelete != true).ToList();
foreach (var pgs in pages)
XmlElement _element = pages_XMLCONTENTS.CreateElement("url", pages_XMLCONTENTS.DocumentElement.NamespaceURI);
XmlElement loc = pages_XMLCONTENTS.CreateElement("loc", pages_XMLCONTENTS.DocumentElement.NamespaceURI);
loc.InnerText = www + Tools.CreateLinkSingleLang("[CORPORATEPAGES]", "[CORPORATEPAGE]", pgs.id, pgs.pages_contents.Where(xw => xw.languageID == lng.id).FirstOrDefault().title, lng.id);
_element.AppendChild(loc);
XmlElement lastmod = pages_XMLCONTENTS.CreateElement("lastmod", pages_XMLCONTENTS.DocumentElement.NamespaceURI);
lastmod.InnerText = DateTime.Now.ToString();
_element.AppendChild(lastmod);
XmlElement changefreq = pages_XMLCONTENTS.CreateElement("changefreq", pages_XMLCONTENTS.DocumentElement.NamespaceURI);
changefreq.InnerText = "daily";
_element.AppendChild(changefreq);
XmlElement priority = pages_XMLCONTENTS.CreateElement("priority", pages_XMLCONTENTS.DocumentElement.NamespaceURI);
priority.InnerText = "0.5";
_element.AppendChild(priority);
pages_XMLCONTENTS.DocumentElement.AppendChild(_element);
XmlTextWriter pages_write = new XmlTextWriter(pages_xmlurl, null);
pages_write.Formatting = Formatting.Indented;
pages_XMLCONTENTS.WriteContentTo(pages_write);
pages_write.Close();
#endregion
【讨论】:
这只是重复了现有投票答案的一部分。以上是关于可以将 XSLT 样式表添加到序列化的 XML 文档吗?的主要内容,如果未能解决你的问题,请参考以下文章
当我将 XSLT 样式表应用到 XML 文件时,啥也没有出现