XSLTxml到json跳过根节点+如何将属性复制为子节点



我正在尝试使用XSLT3.0将XML转换为json,降低所有键的大小,并将第一个属性(如果有的话(作为json子属性移动。因此,给定以下(伪(输入XML:

<FOO id="1">
<BAR xy="2">
<SPAM>N</SPAM>
</BAR>
</FOO>

我在等

{ 
"foo" : { 
"id" : "1",
"bar" : { 
"xy" : "2",
"spam" : "N" 
} 
}
}

使用此XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:output method="xml" indent='true' omit-xml-declaration='yes'/>

<xsl:template match="dummy">
<xsl:variable name="json-xml">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>

<!--no children-->
<xsl:template match="*[not(*)]">
<string key="{lower-case(local-name())}">{.}</string>
</xsl:template>

<xsl:template match="*[*]">
<xsl:param name="key" as="xs:boolean" select="true()"/>
<map>
<xsl:if test="$key">
<xsl:attribute name="key" select="lower-case(local-name())"/>
</xsl:if>
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:choose>
<xsl:when test="current-group()[2]">
<array key="{lower-case(local-name())}">
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="false()"/>
</xsl:apply-templates>
</array>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="true()"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</map>
</xsl:template>
</xsl:stylesheet>

我得到(注意dummy模式跳过json转换(,

<map xmlns="http://www.w3.org/2005/xpath-functions" key="foo">
<map key="bar">
<string key="spam">N</string>
</map>
</map>

看起来不错,但当我调用JSON转换时(通过用/替换dummy(,我得到:

{ "bar" : 
{ "spam" : "N" } }

->CCD_ 4节点消失。

我还没想好如何";移动";第一个属性(任意,可以有任何名称(作为子节点-如果有人知道,请欣赏一小段。

最后,没什么大不了的,但我降低了每个模板中的密钥。是否可以一次进行转换,或者在源XML中进行转换之前,或者在模板化之后,在结果XML中(在jsonification之前(进行转换?

请参阅-https://xsltfiddle.liberty-development.net/jyfAiDC/2

(顺便感谢@Martin Honnen提供了这个非常有用的工具!!(

您可以使用

<xsl:template match="/">
<xsl:variable name="json-xml">
<map>
<xsl:apply-templates/>
</map>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>

也许是为了更接近你可能想要的。但是我还不明白您想对XML中的属性做什么。

key属性只对表示映射中的条目的元素有意义,因此,除非该元素有一个名为map的父元素,否则将其包含在元素中是没有意义的。您需要在结构中使用另一层贴图。

感谢Martin&Michael的map包装提示。同意,尽管这是树中不必要的级别。

对于将XML属性呈现为子节点(假设只有一个子节点(,我在模板中的第一个test(条件映射属性(之后添加了以下内容:

<xsl:if test="@*[1]">
<string key="{name(@*[1])}">{@*[1]}</string>
</xsl:if>

最后,要一次性将所有中间key属性转换为小写,而不是在多个模板中单独转换,我认为需要在传递给xml-to-json函数之前解析结果树。

不值得……但这将是XSLT 4.0(?(中的一个不错的功能选项,即新的xml-to-json选项force-key-case=lower/upper

最新更新