使用 xslt 将紧凑的 xml 表示扩展为更详细的表示
Expand compact xml representation to more verbose representation using xslt
我正在尝试将学习 xslt 作为一种爱好,我感兴趣的用例之一是将某些组件的定义扩展为它们的完整形式。一个例子应该阐明我的意思。例如如果我的输入 xml 看起来像:
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system"/>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system"/>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system"/>
</galaxy>
</galaxies>
<systems>
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system"/>
<planet name="mercury"/>
</system>
<system name="windmill system">
<planet name="windy"/>
</system>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</systems>
</universe>
我的输出 xml 会在星系定义中递归地扩展这些系统定义(例如太阳系中的地球系统)并且在定义出现的每个地方(例如地球系统出现在两个不同的地方)系统)。系统部分将被删除:
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
<planet name="mercury"/>
</system>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system">
<planet name="windy"/>
</system>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</galaxy>
</galaxies>
</universe>
我对 xslt 还很陌生,到目前为止,我遵循的思路是以某种方式将这些组件块定义为变量,并在(第二?)遍中适当地插入它们.然而,当我在谷歌上搜索并阅读一些试图找到例子的时候,我并没有很成功。我想知道这是否完全可能(我希望如此),以及我需要使用哪些概念来实现这一目标。示例片段会很有帮助。
谢谢!
XSLT 有一个非常有用的 keys 机制来解析交叉引用。为了演示它是如何工作的,我首先修改了您的 XML 示例以避免循环引用:
XML
<universe>
<galaxies>
<galaxy name="milky way">
<system-ref name="solar system"/>
</galaxy>
<galaxy name="lactose free">
<system-ref name="windmill system"/>
</galaxy>
<galaxy name="parallelish solar system">
<system-ref name="the earth system"/>
</galaxy>
</galaxies>
<systems>
<system name="solar system">
<planet name="pluto"/>
<system-ref name="the earth system"/>
<planet name="mercury"/>
</system>
<system name="windmill system">
<planet name="windy"/>
</system>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</systems>
</universe>
XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="system-by-name" match="system" use="@name" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="system-ref">
<xsl:apply-templates select="key('system-by-name', @name)"/>
</xsl:template>
<xsl:template match="systems"/>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
<planet name="mercury"/>
</system>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system">
<planet name="windy"/>
</system>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</galaxy>
</galaxies>
</universe>
我正在尝试将学习 xslt 作为一种爱好,我感兴趣的用例之一是将某些组件的定义扩展为它们的完整形式。一个例子应该阐明我的意思。例如如果我的输入 xml 看起来像:
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system"/>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system"/>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system"/>
</galaxy>
</galaxies>
<systems>
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system"/>
<planet name="mercury"/>
</system>
<system name="windmill system">
<planet name="windy"/>
</system>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</systems>
</universe>
我的输出 xml 会在星系定义中递归地扩展这些系统定义(例如太阳系中的地球系统)并且在定义出现的每个地方(例如地球系统出现在两个不同的地方)系统)。系统部分将被删除:
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
<planet name="mercury"/>
</system>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system">
<planet name="windy"/>
</system>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</galaxy>
</galaxies>
</universe>
我对 xslt 还很陌生,到目前为止,我遵循的思路是以某种方式将这些组件块定义为变量,并在(第二?)遍中适当地插入它们.然而,当我在谷歌上搜索并阅读一些试图找到例子的时候,我并没有很成功。我想知道这是否完全可能(我希望如此),以及我需要使用哪些概念来实现这一目标。示例片段会很有帮助。
谢谢!
XSLT 有一个非常有用的 keys 机制来解析交叉引用。为了演示它是如何工作的,我首先修改了您的 XML 示例以避免循环引用:
XML
<universe>
<galaxies>
<galaxy name="milky way">
<system-ref name="solar system"/>
</galaxy>
<galaxy name="lactose free">
<system-ref name="windmill system"/>
</galaxy>
<galaxy name="parallelish solar system">
<system-ref name="the earth system"/>
</galaxy>
</galaxies>
<systems>
<system name="solar system">
<planet name="pluto"/>
<system-ref name="the earth system"/>
<planet name="mercury"/>
</system>
<system name="windmill system">
<planet name="windy"/>
</system>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</systems>
</universe>
XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="system-by-name" match="system" use="@name" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="system-ref">
<xsl:apply-templates select="key('system-by-name', @name)"/>
</xsl:template>
<xsl:template match="systems"/>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<universe>
<galaxies>
<galaxy name="milky way">
<system name="solar system">
<planet name="pluto"/>
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
<planet name="mercury"/>
</system>
</galaxy>
<galaxy name="lactose free">
<system name="windmill system">
<planet name="windy"/>
</system>
</galaxy>
<galaxy name="parallelish solar system">
<system name="the earth system">
<planet name="earth"/>
<satellite name="moon"/>
</system>
</galaxy>
</galaxies>
</universe>