使用自定义 XSLT 将 XML 转换为 JSON 会丢失花括号
Posted
技术标签:
【中文标题】使用自定义 XSLT 将 XML 转换为 JSON 会丢失花括号【英文标题】:Transforming XML to JSON with custom XSLT looses curly braces 【发布时间】:2014-05-03 21:56:54 【问题描述】:我有一个 .NET 库,它使用 XSLT 文件将啤酒 xml 文件转换为 web 应用程序的 json。
XSLT 文件看起来很像这样:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes" />
<xsl:template match="RECIPES">
"description":
"name": "<xsl:value-of select="NAME"/>",
"style": "<xsl:value-of select="STYLE/NAME"/>",
...
我正在使用 c# 中的这段代码进行转换:
using(var writer = new StringWriter())
_xsltCompiler.Transform(_document, null, writer);
json = writer.ToString();
现在,问题是输出中缺少大括号和空格。它曾经工作过。从源代码控制历史来看,我最近没有看到明显的变化。有关如何解决此问题的任何建议?
【问题讨论】:
XSLT 通常是生成 JSON 的错误工具。它不能可靠地做到这一点,它不知道 JSON 是如何工作的。这是错误的方法,您应该使用正确的 JSON 序列化程序。 .NET 有很多,选择一个。考虑一下这种方法,它会为您节省不止一个头痛:***.com/questions/12037085/… @Tomalak 不确定为什么您认为 XSLT 是一个糟糕的选择? OP 希望将 XML 转换为字符串,尽管是格式化的字符串。为什么 XSLT 不是一个好的选择? @LegoStormtroopr,如果没有别的(可能没有别的),正确的字符串的 JSON 转义在 XSLT 中会非常不方便,因为它需要在大型值映射(包括大多数非 ASCII Unicode 点)。虽然我倾向于在人为可能的情况下给予 XSLT 怀疑的好处,但我认为 Tomolak 是正确的。 @AndersNygaard 那是default behavior for XSLT。听我的建议。 XSLT 不是解决此问题的正确工具。它无法进行正确的字符转义,并且很容易产生语法错误的 JSON,而您却无法注意到——而且很难解决这个问题。使用 LINQ to XML 在 .NET 中生成您需要的对象图,并将该图直接序列化为 JSON。这样就可以安全、正确、更快地完成工作,而且很可能只需要更少的代码行。 @LegoStormtroopr OP 不想将 XML 转换为字符串。他想将其转换为 JSON,它不是字符串。 JSON 是一种序列化形式的对象图,具有专门且非常复杂的语法规则,就像 XML 本身一样。 JSON 输出没有内置到 XSLT 中,因此它不能可靠地遵守 JSON 的形式语义。在这一点上,它变成了一场碰碰运气的游戏,生成正确 JSON 的 XSL 样式表将非常复杂(至少比 OP 的尝试复杂得多)。另外:已经有 .NET 的 JSON 序列化器,为什么还要构建另一个劣质的序列化器? 【参考方案1】:我建议最初将其转换为 xml 并将其存储到变量中,然后应用标准/通用模板将其转换为 JSON。我会使用 XSLT 2.0 或 3.0 来实现这一点,并实现 xml-to-json()
。
这是我对上面示例的解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes" />
<xsl:template match="RECIPES">
<xsl:variable name="xml">
<description>
<xsl:element name="name">
<xsl:value-of select="NAME"/>
</xsl:element>
<xsl:element name="style">
<xsl:value-of select="STYLE/NAME"/>
</xsl:element>
</description>
</xsl:variable>
<xsl:apply-templates select="$xml" mode="xml-to-json"/>
</xsl:template>
<!-- Object or Element Property-->
<xsl:template match="*" mode="xml-to-json">
"<xsl:value-of select="name()"/>" :
<xsl:call-template name="Properties">
<xsl:with-param name="parent" select="'Yes'"></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Array Element -->
<xsl:template match="*" mode="ArrayElement">
<xsl:call-template name="Properties"/>
</xsl:template>
<!-- Object Properties -->
<xsl:template name="Properties">
<xsl:param name="parent"></xsl:param>
<xsl:variable name="childName" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="not(*|@*)">
<xsl:choose>
<xsl:when test="$parent='Yes'">
<xsl:text>"</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise>"<xsl:value-of select="name()"/>":"<xsl:value-of select="."/>"</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="count(*[name()=$childName]) > 1"> "<xsl:value-of select="$childName"/>" :[<xsl:apply-templates select="*" mode="ArrayElement"/>] </xsl:when>
<xsl:otherwise><xsl:apply-templates select="@*" mode="xml-to-json"/><xsl:apply-templates select="*" mode="xml-to-json"/></xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
</xsl:template>
</xsl:stylesheet>
【讨论】:
这个答案引起了人们对不良 cmets 的不良问题的关注。请考虑为***.com/questions/13007280/… 投稿以上是关于使用自定义 XSLT 将 XML 转换为 JSON 会丢失花括号的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 XSLT 将单个子 xml 元素转换为 Json 数组
如何停止 xslt3.0 的 xml-to-json() 函数将数字转换为指数表示法