首页 > 解决方案 > 在不使用任何硬编码元素的情况下,使用 XSLT 1.0 将给定的 xml 概括为 json 的正确方法是什么?

问题描述

我正在处理以下 XML 文档,我想在其中将 XML 转换为 JSON。

<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<CATEGORY>
<COUNT> 5 </COUNT>
</CATEGORY>
<TYPE>
<COUNT> 10 </COUNT>
</TYPE>
<FRUITS>
<NAME>APPLE</NAME>
<FRUIT_COUNT>10</FRUIT_COUNT>
</FRUITS>
<FRUITS>
<NAME>ORANGES</NAME>
<FRUIT_COUNT>20</FRUIT_COUNT>
</FRUITS>
</DATA>

我要为上述 XML 转换为的 JSON 如下所示。

{
"CATEGORY":5,
"TYPE": 10,
"FRUITS":{
    "APPLE": 10,
    "ORANGES": 20
}
}

所以我编写了下面的 XSLT 代码来将上面的 XML 转换为 JSON。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/DATA">


<xsl:text>{"CATEGORY":</xsl:text>
<xsl:value-of select="CATEGORY/COUNT"/>
<xsl:text>,</xsl:text>

<xsl:text>"TYPE":</xsl:text>
<xsl:value-of select="TYPE/COUNT"/>
<xsl:text>,</xsl:text>

<xsl:text>
"FRUITS": {
</xsl:text>
<xsl:for-each select="FRUITS">
<xsl:text>"</xsl:text>
<xsl:value-of select="NAME"/>
<xsl:text>":</xsl:text>
<xsl:value-of select="FRUIT_COUNT"/>
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
<xsl:text>}}</xsl:text>

</xsl:template>
</xsl:stylesheet>

上面的 XSLT 按预期将 XML 转换为 JSON。但是,我无法概括上述 XSLT,因此如果添加了新字段,我不必像在上述 XSLT 中那样对其进行硬编码。什么是概括 XSLT 以便它在没有硬编码的情况下创建 JSON 的正确方法?在概括它时我做错了什么吗?

更新:

我尝试使用以下 XSLT 概括 XSLT 以将 XML 转换为 JSON:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/DATA">

<xsl:text>{</xsl:text>
<xsl:for-each select="/DATA">
  <xsl:for-each select="*">
    <xsl:text>"</xsl:text><xsl:value-of select="local-name()"/><xsl:text>":</xsl:text><xsl:value-of select="."/>
<xsl:if test="position()!=last()">,</xsl:if>
  </xsl:for-each>  
</xsl:for-each>
<xsl:text>}</xsl:text>
</xsl:template>
</xsl:stylesheet>

但是当我使用上述 XSLT 时的输出如下:

{"CATEGORY":
 5 
,"TYPE":
 10 
,"FRUITS":
APPLE
10
,"FRUITS":
ORANGES
20
}

我如何概括嵌套的 JSON,以便我可以获得正确格式的 JSON。在修改后的转换后的 JSON 中,我得到了两次“FRUITS”,它不是我想要实现的嵌套格式。

标签: xmlxsltxslt-1.0

解决方案


确实没有正确的方法来概括这一点。你可能需要想出一套你想要实施的规则,并以此为基础。

  1. 如果根元素的子元素DATA没有 a NAME,则将该元素作为属性输出,其名称为元素名称,文本值作为其值。
  2. 如果子元素确实有NAME,则使用元素名称的名称输出单个属性,并且对于具有相同名称的所有元素,输出基于 的嵌套属性NAME

在这种情况下,您可以像这样编写 XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>

<xsl:template match="DATA" priority="2">
  <xsl:text>{</xsl:text>
    <xsl:apply-templates />
  <xsl:text>}</xsl:text>
</xsl:template>

<xsl:template match="*[not(NAME)]">
  <xsl:text>"</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>":</xsl:text>
  <xsl:value-of select="normalize-space()"/>
  <xsl:text>,</xsl:text>
</xsl:template>

<xsl:template match="*[NAME][1]">
  <xsl:text>"</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>": {</xsl:text>
  <xsl:for-each select="../*[name() = name(current())]">
    <xsl:text>"</xsl:text>
    <xsl:value-of select="NAME"/>
    <xsl:text>":</xsl:text>
    <xsl:value-of select="*[not(self::NAME)]"/>
    <xsl:if test="position()!=last()">,</xsl:if>
  </xsl:for-each>
  <xsl:text>}</xsl:text>
</xsl:template>

<xsl:template match="*[NAME][position() > 1]" />
</xsl:stylesheet>

推荐阅读