使用自定义XSLT将XML转换为JSON会丢失花括号。

5
我有一个使用XSLT文件将啤酒xml文件转换为Web应用程序中的json的.NET库。
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();
}

现在的问题是输出中缺少花括号和空格。但它之前是正常工作的。从源代码控制历史记录中我没有发现任何明显的更改。有什么建议可以修复这个问题吗?

5
XSLT通常不适合生成JSON,它无法可靠地完成此任务,也不理解JSON的工作原理。使用正确的JSON序列化工具是正确的方法。.NET有很多选择,可以选择其中之一。考虑这种方法,它会帮你省去不少麻烦:https://dev59.com/pmct5IYBdhLWcg3whtqh - Tomalak
1
@Tomalak,不确定您为什么认为XSLT不适合这个任务?OP想要将XML转换为字符串,尽管是格式化的字符串。为什么XSLT不是一个好选择呢? - user764357
4
@LegoStormtroopr,如果没有其他的问题(可能没有),在XSLT中正确转义JSON字符串将非常不方便,因为它需要在一个包含大量值的映射中进行单字符到多字符的表示(包括大部分非ASCII Unicode点)。尽管我倾向于在人类可能的情况下给予XSLT最大的优惠,但我认为Tomolak是正确的。 - harpo
2
@AndersNygaard 这是 XSLT 的默认行为。请听取我的建议,XSLT 不是这个工具的正确选择。它无法正常进行字符转义,并且很容易生成语法错误的 JSON,你没有办法注意到这个问题,而且修复很困难。使用 LINQ to XML 在 .NET 中直接生成您所需的对象图并将其直接序列化为 JSON。这样可以安全、正确地完成工作,速度更快,而且可能会用更少的代码行。 - Tomalak
1
@Tomalak,我会考虑你的建议,将XML转换为对象结构,然后转换为JSON。你知道,我们确实尝试过一些直接从XML转换为JSON的框架,但那并不是正确的方法。 - Anders Nygaard
显示剩余5条评论
1个回答

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>&quot;</xsl:text>
                                    <xsl:value-of select="."/>
                                    <xsl:text>&quot;</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>

这个回答引起了对一个带有恶评的糟糕问题的关注。请考虑为 https://dev59.com/lWcs5IYBdhLWcg3wPxrN 做出贡献。 - Alejandro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接