我试图使用XSLT将XML命名空间XML转换为JSON数据,如下所示:
基本上,如果XML元素有一个表单元素的节点,xmnls=“urn:ietf:params:xml:ns:yang:ietf-xmnls=”。JSON的转换应该是"ietf-modulename:element“,如下例所示
XML:
<notification
xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
<event-time>2013-12-21T00:01:00Z</event-time>
<event>
<event-class>fault</event-class>
<reporting-entity>
<card>Ethernet0</card>
</reporting-entity>
<severity>major</severity>
</event>
</notification>
JSON Conversion:
{
"ietf-restconf:notification": {
"event-time": "2013-12-21T00:01:00Z",
"event": {
"event-class": "fault",
"reporting-entity": { "card": "Ethernet0" },
"severity": "major"
}使用以下xslt:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">{
<xsl:apply-templates select="*"/>}
</xsl:template>
<!-- Object or Element Property-->
<xsl:template match="*">
"<xsl:value-of select="name()"/>" : <xsl:call-template name="Properties"/>
</xsl:template>
<!-- Array Element -->
<xsl:template match="*" mode="ArrayElement">
<xsl:call-template name="Properties"/>
</xsl:template>
<!-- Object Properties -->
<xsl:template name="Properties">
<xsl:variable name="childName" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="not(*|@*)">"<xsl:value-of select="."/>"</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="@*"/>
<xsl:apply-templates select="*"/>
}</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
</xsl:template>
<!-- Attribute Property -->
<xsl:template match="@*">"<xsl:value-of select="name()"/>" : "<xsl:value-of select="."/>",
</xsl:template>
</xsl:stylesheet>但是名称空间在这里被删除了。如何编辑XSL文件以在JSON中转换为"ietf-restconf:notification“?
另一个例子是:
<interfaces
xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>0/4</name>
<type
xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd
</type>
<enabled>false</enabled>
<link-up-down-trap-enable>enabled</link-up-down-trap-enable>
<ipv4
xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<enabled>false</enabled>
</ipv4>
<ipv6
xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<enabled>false</enabled>
<mtu>1500</mtu>
<forwarding>false</forwarding>
<dup-addr-detect-transmits>1</dup-addr-detect-transmits>
<autoconf>
<create-global-addresses>false</create-global-addresses>
</autoconf>
</ipv6>
</interface>
</interfaces> 应该映射到
{"ietf-interfaces:interfaces": {
"interface": {
"name": "0/4",
"iana-if-type:type": "ianaift:ethernetCsmacd
",
"enabled": "false",
"link-up-down-trap-enable": "enabled",
"ietf-ip:ipv4": {
"enabled": "false"
},
"ietf-ip:ipv6": {
"enabled": "false",
"mtu": "1500",
"forwarding": "false",
"dup-addr-detect-transmits": "1",
"autoconf": {
"create-global-addresses": "false"
}
}
}
}}发布于 2015-12-04 07:37:14
您的要求中最困难的部分是前缀。
当你说(略为提高可读性)时:
基本上,如果XML元素有一个表单元素
xmnls="urn:ietf:params:xml:ns:yang:ietf-modulename"的节点,那么JSON转换应该是"ietf-modulename: element“,如下例所示
您似乎在谈论具有xmlns=""命名空间声明的元素。这不是XSLT处理器在XML中看到的属性。它是绑定到元素的命名空间(并且是元素的后代,除非他们指定了不同的名称空间)。
所以,与notification元素不同,它实际上是
{urn:ietf:params:xml:ns:yang:ietf-restconf}notification元素。
在您的示例中,所有子代元素也位于同一个命名空间中。
以event-time为例:
{urn:ietf:params:xml:ns:yang:ietf-restconf}event-time下面是一个很好的名称空间引用,以获得更好的解释:http://www.jclark.com/xml/xmlns.htm
我认为您唯一能做的就是检查根元素上的命名空间uri,然后检查默认名称空间是否已经更改。
看一下您的示例,您似乎希望在上一个:之后获得uri的一部分。您可以通过使用递归模板调用来实现这一点,但是在XSLT2.0中会容易得多。
下面是一个例子。我是为了可读性而缩进的,但没有必要。只需删除名为indent和indent变量的模板及其引用即可。(在XSLT2.0中,这也要容易得多。)
它并不全面,但适用于您的示例,应该给您一个起点。
在这里也可以看到示例:http://xsltransform.net/6r5Gh3i (需要在服务可用时进行更新)
XML输入
<interfaces
xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface attr="x">
<name>0/4</name>
<type
xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd
</type>
<enabled>false</enabled>
<link-up-down-trap-enable>enabled</link-up-down-trap-enable>
<ipv4
xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<enabled>false</enabled>
</ipv4>
<ipv6
xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<enabled>false</enabled>
<mtu>1500</mtu>
<forwarding>false</forwarding>
<dup-addr-detect-transmits>1</dup-addr-detect-transmits>
<autoconf>
<create-global-addresses>false</create-global-addresses>
</autoconf>
</ipv6>
</interface>
</interfaces>XSLT1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*" priority="1">
<xsl:variable name="prefix">
<xsl:call-template name="getPrefix">
<xsl:with-param name="uri" select="namespace-uri()"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat('{"',$prefix,local-name(),'"')"/>
<xsl:text>: {
</xsl:text>
<xsl:apply-templates/>
<xsl:text>}}</xsl:text>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:variable name="indent">
<xsl:call-template name="indent">
<xsl:with-param name="level" select="count(ancestor::*)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="prefix">
<xsl:if test="namespace-uri()!=namespace-uri(..)">
<xsl:call-template name="getPrefix">
<xsl:with-param name="uri" select="namespace-uri()"/>
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:value-of select="concat($indent,'"',$prefix,local-name(),'": ')"/>
<xsl:apply-templates/>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*[*]">
<xsl:variable name="indent">
<xsl:call-template name="indent">
<xsl:with-param name="level" select="count(ancestor::*)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="prefix">
<xsl:if test="namespace-uri()!=namespace-uri(..)">
<xsl:call-template name="getPrefix">
<xsl:with-param name="uri" select="namespace-uri()"/>
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:value-of select="concat($indent,'"',$prefix,local-name(),'"')"/>
<xsl:text>: {
</xsl:text>
<xsl:apply-templates/>
<xsl:value-of select="concat($indent,'}')"/>
<xsl:if test="following-sibling::*">,</xsl:if>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="concat('"',normalize-space(),'"')"/>
</xsl:template>
<xsl:template name="indent">
<xsl:param name="level"/>
<xsl:if test="$level >= 1">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:if test="$level - 1 >= 1">
<xsl:call-template name="indent">
<xsl:with-param name="level" select="$level - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="getPrefix">
<xsl:param name="uri"/>
<xsl:if test="namespace-uri()">
<xsl:choose>
<xsl:when test="contains($uri,':')">
<xsl:call-template name="getPrefix">
<xsl:with-param name="uri" select="substring-after($uri,':')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$uri"/>
<xsl:if test="$uri">:</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>输出
{"ietf-interfaces:interfaces": {
"interface": {
"name": "0/4",
"type": "ianaift:ethernetCsmacd",
"enabled": "false",
"link-up-down-trap-enable": "enabled",
"ietf-ip:ipv4": {
"enabled": "false"
},
"ietf-ip:ipv6": {
"enabled": "false",
"mtu": "1500",
"forwarding": "false",
"dup-addr-detect-transmits": "1",
"autoconf": {
"create-global-addresses": "false"
}
}
}
}}这个输出和您请求的输出之间唯一的区别是使用type元素。迈克尔在回答中最好地解释了这一点:
注意,在您的(新)示例中,
type元素与其父节点位于同一个名称空间中。命名空间声明xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"不影响它。实际上,它不影响整个XML中的任何节点。
发布于 2015-12-04 11:31:58
在输出元素的名称之前,尝试添加以下内容:
<xsl:if test="namespace-uri()!=namespace-uri(..)">
<xsl:value-of select="concat(substring-after(namespace-uri(), 'urn:ietf:params:xml:ns:yang:'), ':')"/>
</xsl:if>这部分是基于您链接到的标准的以下语句:
必须为顶级JSON对象的所有成员使用命名空间限定成员名称,然后每当节点及其父节点的命名空间不同时,也必须使用命名空间限定成员名。
部分原因在于你的声明:
我的要求是,应该提取"urn:ietf:params:xml:ns:yang:“之后的所有内容,并将其作为前缀添加到任何具有命名空间的元素中。
请注意,在您的(新)示例中,type元素与其父节点位于同一个名称空间中的。命名空间声明xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"不影响它。实际上,它不影响整个XML中的任何节点。
与您的问题无关:我建议您使用xsl:text提供JSON标记和缩进。这将使样式表更加可读性更强,更易于修改。
https://stackoverflow.com/questions/34071614
复制相似问题