XSLT 1.0 - 运行 一个模板基于另一个模板的结果
XSLT 1.0 - Running a template on the result of another template
我想知道 XSLT 1.0 是如何完成这一转换的,该转换将一个模板的结果作为单个 .xslt 文件中另一个模板的输入传递:
Raw XML Input > call-template(1) > re-formatted XML > call-template(2) on the re-formatted XML
案例:
我想写一个模板来重新排列一个xml,使属性成为元素;然后 运行 另一个模板在第一个模板的结果 xml 上删除重复项。我可以有两个 xsl 文件,并将第一个转换的结果传递给第二个。但是,我想在一个 xslt 中完成。
原始输入xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<resource>
<properties>
<property name="name" value="Foo"/>
<property name="service" value="Bar"/>
<property name="version" value="1"/>
</properties>
</resource>
<resource>
<properties>
<property name="name" value="Foo"/>
<property name="service" value="Bar"/>
<property name="version" value="2"/>
</properties>
</resource>
<resource>
<properties>
<property name="name" value="AnotherFoo"/>
<property name="service" value="AnotherBar"/>
<property name="version" value="1"/>
</properties>a
</resource>
</resources>
当我应用以下 xslt 时:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes" />
<xsl:template name="attributes-to-elements" match="/resources">
<xsl:call-template name="get-resources" />
</xsl:template>
<xsl:template name="get-resources">
<xsl:text>
</xsl:text>
<products>
<xsl:for-each select="resource">
<xsl:call-template name="convert-attributes-to-elements" />
</xsl:for-each>
</products>
</xsl:template>
<xsl:template name="convert-attributes-to-elements">
<product>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>
我能够在没有版本的情况下重新格式化 xml 并获得不包含版本的输出并且属性已成为元素:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>AnotherFoo</name>
<service>AnotherBar</service>
</product>
</products>
现在,我想要的是将此修改后的 xml 作为 输入 xml 传递给某个模板并删除重复项。最后,我想得到一个 xml 像:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>AnotherFoo</name>
<service>AnotherBar</service>
</product>
</products>
我会使用一种模式来分离处理步骤,当然在 XSLT 1.0 中您还需要扩展函数,如 exsl:node-set
或 msxsl:node-set
以便能够进一步处理创建的结果树片段在另一个模板中:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="msxsl exsl">
<xsl:output method="xml" indent="yes" />
<xsl:key name="group" match="product" use="concat(name, '|', service)"/>
<xsl:template match="@* | node()" mode="step2">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="step2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product[not(generate-id() = generate-id(key('group', concat(name, '|', service))[1]))]" mode="step2"/>
<xsl:template name="attributes-to-elements" match="/resources">
<xsl:variable name="step1-rtf">
<xsl:call-template name="get-resources" />
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($step1-rtf)/*" mode="step2"/>
</xsl:template>
<xsl:template name="get-resources">
<xsl:text>
</xsl:text>
<products>
<xsl:for-each select="resource">
<xsl:call-template name="convert-attributes-to-elements" />
</xsl:for-each>
</products>
</xsl:template>
<xsl:template name="convert-attributes-to-elements">
<product>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>
您需要检查您的 XSLT 处理器是否支持 exsl:node-set
,MSXML 需要 msxsl:node-set
。
这一切都可以一次完成,如果你想:
XSLT 1.0
<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="k"
match="resource"
use="concat(properties/property[@name='name']/@value, '|', properties/property[@name='service']/@value)"
/>
<xsl:template match="/resources">
<products>
<xsl:apply-templates select="resource[count(. | key('k', concat(properties/property[@name='name']/@value, '|', properties/property[@name='service']/@value))[1]) = 1]"/>
</products>
</xsl:template>
<xsl:template match="resource">
<product>
<xsl:copy-of select="@id"/>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>
我想知道 XSLT 1.0 是如何完成这一转换的,该转换将一个模板的结果作为单个 .xslt 文件中另一个模板的输入传递:
Raw XML Input > call-template(1) > re-formatted XML > call-template(2) on the re-formatted XML
案例:
我想写一个模板来重新排列一个xml,使属性成为元素;然后 运行 另一个模板在第一个模板的结果 xml 上删除重复项。我可以有两个 xsl 文件,并将第一个转换的结果传递给第二个。但是,我想在一个 xslt 中完成。
原始输入xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<resource>
<properties>
<property name="name" value="Foo"/>
<property name="service" value="Bar"/>
<property name="version" value="1"/>
</properties>
</resource>
<resource>
<properties>
<property name="name" value="Foo"/>
<property name="service" value="Bar"/>
<property name="version" value="2"/>
</properties>
</resource>
<resource>
<properties>
<property name="name" value="AnotherFoo"/>
<property name="service" value="AnotherBar"/>
<property name="version" value="1"/>
</properties>a
</resource>
</resources>
当我应用以下 xslt 时:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes" />
<xsl:template name="attributes-to-elements" match="/resources">
<xsl:call-template name="get-resources" />
</xsl:template>
<xsl:template name="get-resources">
<xsl:text>
</xsl:text>
<products>
<xsl:for-each select="resource">
<xsl:call-template name="convert-attributes-to-elements" />
</xsl:for-each>
</products>
</xsl:template>
<xsl:template name="convert-attributes-to-elements">
<product>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>
我能够在没有版本的情况下重新格式化 xml 并获得不包含版本的输出并且属性已成为元素:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>AnotherFoo</name>
<service>AnotherBar</service>
</product>
</products>
现在,我想要的是将此修改后的 xml 作为 输入 xml 传递给某个模板并删除重复项。最后,我想得到一个 xml 像:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<name>Foo</name>
<service>Bar</service>
</product>
<product>
<name>AnotherFoo</name>
<service>AnotherBar</service>
</product>
</products>
我会使用一种模式来分离处理步骤,当然在 XSLT 1.0 中您还需要扩展函数,如 exsl:node-set
或 msxsl:node-set
以便能够进一步处理创建的结果树片段在另一个模板中:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="msxsl exsl">
<xsl:output method="xml" indent="yes" />
<xsl:key name="group" match="product" use="concat(name, '|', service)"/>
<xsl:template match="@* | node()" mode="step2">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="step2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product[not(generate-id() = generate-id(key('group', concat(name, '|', service))[1]))]" mode="step2"/>
<xsl:template name="attributes-to-elements" match="/resources">
<xsl:variable name="step1-rtf">
<xsl:call-template name="get-resources" />
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($step1-rtf)/*" mode="step2"/>
</xsl:template>
<xsl:template name="get-resources">
<xsl:text>
</xsl:text>
<products>
<xsl:for-each select="resource">
<xsl:call-template name="convert-attributes-to-elements" />
</xsl:for-each>
</products>
</xsl:template>
<xsl:template name="convert-attributes-to-elements">
<product>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>
您需要检查您的 XSLT 处理器是否支持 exsl:node-set
,MSXML 需要 msxsl:node-set
。
这一切都可以一次完成,如果你想:
XSLT 1.0
<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="k"
match="resource"
use="concat(properties/property[@name='name']/@value, '|', properties/property[@name='service']/@value)"
/>
<xsl:template match="/resources">
<products>
<xsl:apply-templates select="resource[count(. | key('k', concat(properties/property[@name='name']/@value, '|', properties/property[@name='service']/@value))[1]) = 1]"/>
</products>
</xsl:template>
<xsl:template match="resource">
<product>
<xsl:copy-of select="@id"/>
<name>
<xsl:value-of select="properties/property[@name='name']/@value" />
</name>
<service>
<xsl:value-of select="properties/property[@name='service']/@value" />
</service>
</product>
</xsl:template>
</xsl:stylesheet>