在 XSLT 3.0 中,我想以标准方式处理json-to-xml()
由包含对象和简单值数组的 JSON 输入的调用隐式生成的 XML。
使用 XSLT 3.0 函数将 JSON 转换为 XML
和
XSLT 3.0 中的 JSON 到 XML 转换中给出的解决方案似乎很简单。但是,数组的模板没有被调用。尽管以第二种解决方案为例,其数组模板规则的匹配条件,即
<xsl:template match="array">
和
<xsl:template match="array[@key]/*">
比第一个模板规则更具体,即<xsl:template match="*[@key]">
。我似乎记得 XSLT 优先规则的一般经验法则是:“更具体的规则胜过更一般的规则。”
举一个受上述解决方案启发的我自己的例子,在下面的样式表中,模板<xsl:template match="array[@key='phones']">
和模板都<xsl:template match="array[@key]">
没有被调用:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fn">
<xsl:param name="json">
{
"person":{
"name": "John",
"age": 30,
"address": {
"city": "New York",
"zipcode": "10001"
},
"phones": ["123-4567", "987-6543"]
}
}
<!-- A reminder of what would be produced by a call to <xsl:copy-of select="$XMLfromJSON" />:
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="person">
<string key="name">John</string>
<number key="age">30</number>
<map key="address">
<string key="city">New York</string>
<string key="zipcode">10001</string>
</map>
<array key="phones">
<string>123-4567</string>
<string>987-6543</string>
</array>
</map>
</map>
-->
</xsl:param>
<xsl:variable name="XMLfromJSON" select="json-to-xml($json)" />
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="$XMLfromJSON/*"/>
</xsl:template>
<!-- Universal template for processing elements with an attribute "key"-->
<xsl:template match="*[@key]">
<xsl:element name="{@key}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<!-- Specific template for processing arrays named "phones" -->
<xsl:template match="array[@key='phones']">
<xsl:element name="{@key}">
<xsl:for-each select="*">
<value>
<xsl:value-of select="."/>
</value>
</xsl:for-each>
</xsl:element>
</xsl:template>
<!-- Universal fallback-template for processing other arrays -->
<xsl:template match="array[@key]">
<xsl:element name="{@key}">
<xsl:for-each select="*">
<item>
<xsl:apply-templates/>
</item>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
这仅生成以下 XML:
<person>
<name>John</name>
<age>30</age>
<address>
<city>New York</city>
<zipcode>10001</zipcode>
</address>
<phones>123-4567987-6543</phones>
</person>
然而我想要的是以下 XML:
<person>
<name>John</name>
<age>30</age>
<address>
<city>New York</city>
<zipcode>10001</zipcode>
</address>
<phones>
<value>123-4567</value>
<value>987-6543</value>
</phones>
</person>
所以我的第一个问题是:为什么没有调用数组模板?有人能给我解释一下吗?也许参考 XSLT 3.0 优先规则的特定子规则?
我的第二个问题是:如何让这些模板自动调用?
如果这不可能,我的第三个问题是:这里最优雅的(特别是模块化的)解决方案是什么?
我想出了一个产生所需输出的解决方案,即:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fn">
<xsl:param name="json">
{
"person":{
"name": "John",
"age": 30,
"address": {
"city": "New York",
"zipcode": "10001"
},
"phones": ["123-4567", "987-6543"]
}
}
</xsl:param>
<xsl:variable name="XMLfromJSON" select="json-to-xml($json)" />
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="$XMLfromJSON/*"/>
</xsl:template>
<xsl:template match="*[@key]" >
<xsl:element name="{@key}">
<xsl:choose>
<xsl:when test="name() = 'array'">
<xsl:call-template name="process-array"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<!-- Named template for processing arrays -->
<xsl:template name="process-array">
<xsl:for-each select="*">
<value>
<xsl:apply-templates/>
</value>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
但是,我确实希望避免使用任何条件代码(如 xsl:choose 或 xsl:if 和命名模板),而是依赖 XSLT 的处理器规则。
作为可选的第四个问题,并且出于兴趣:我上面引用的第一个链接,即使用 XSLT 3.0 函数将 JSON 转换为 XML
<xsl:copy>
像这样使用-element :
<xsl:copy>
<xsl:apply-templates select="json-to-xml(.)/*"/>
</xsl:copy>
但是,我删除了它,它还是一样。<xsl:copy>
-element 也没有出现在上面第二个链接的非常相似的解决方案中。这个 -element 有什么用途吗<xsl:copy>
?也许在特定情况下?还是它只是多余的?
使用
xmlns:fn="http://www.w3.org/2005/xpath-functions"
declared,您可以匹配fn:array
。如果您希望您的不合格match="array"
匹配 JSON 的 XML 表示中的元素(元素位于命名空间中),那么您可以xpath-default-namespace="http://www.w3.org/2005/xpath-functions"
在 XSLT 中使用。