XSLT 2.0 动态 XPATH 表达式
XSLT 2.0 dynamic XPATH expression
我有一个 XML 文件需要基于 XSLT 2.0 映射文件进行转换。我正在使用 Saxon HE 处理器。
我的映射文件:
<element root="TEST">
<childName condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILD</childName>
<childBez condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILDBEZ</childBez>
</element>
当 CHILD 的文本等于 B 时,我必须复制元素 CHILD 和 CHILDBEZ 以及父元素和根元素。
所以有了这个输入:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<CHILD>A</CHILD>
<CHILDBEZ>ABEZ</CHILDBEZ>
<NotInteresting></NotInteresting>
</MyElement>
<MyElement>
<CHILD>B</CHILD>
<CHILDBEZ>BBEZ</CHILDBEZ>
<NotInteresting2></NotInteresting2>
</MyElement>
</TEST>
所需的输出:
<TEST>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>
到目前为止我有什么(基于这个解决方案):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:param name="mapping" select="document('mapping.xml')"/>
<xsl:key name="map" match="*" use="."/>
<xsl:template match="/">
<xsl:variable name="first-pass">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$first-pass/*"/>
</xsl:template>
<xsl:template match="*" mode="first-pass">
<xsl:param name="parent-path" tunnel="yes"/>
<xsl:variable name="path" select="concat($parent-path, '/', name())"/>
<xsl:variable name="replacement" select="key('map', $path, $mapping)"/>
<xsl:variable name="condition" select="key('map', $path, $mapping)/@condition"/>
<xsl:choose>
<xsl:when test="$condition!= ''">
<!-- if there is a condition defined in the mapping file, check for it -->
</xsl:when>
<xsl:otherwise>
<xsl:element name="{if ($replacement) then name($replacement) else name()}">
<xsl:attribute name="original" select="not($replacement)"/>
<xsl:apply-templates mode="first-pass">
<xsl:with-param name="parent-path" select="$path" tunnel="yes"/>
</xsl:apply-templates>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@original='true' and not(descendant::*/@original='false')]"/>
</xsl:stylesheet>
但问题是无法使用 XSLT 2.0 评估动态 XPATH 表达式。有谁知道解决方法吗?另外我的映射文件有问题。当其中只有一个元素时,它根本不起作用。
如果动态 XPath 评估不是您所选处理器的一个选项,那么生成 XSLT 样式表通常是一个不错的选择。事实上,它通常是一个不错的选择。
一种思考方式是,您的映射文件实际上是一个用非常简单的转换语言编写的程序。有两种执行该程序的方法:您可以编写一个解释器(动态 XPath 评估),或者您可以编写一个编译器(XSLT 样式表生成)。两者都很好。
我有一个 XML 文件需要基于 XSLT 2.0 映射文件进行转换。我正在使用 Saxon HE 处理器。
我的映射文件:
<element root="TEST">
<childName condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILD</childName>
<childBez condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILDBEZ</childBez>
</element>
当 CHILD 的文本等于 B 时,我必须复制元素 CHILD 和 CHILDBEZ 以及父元素和根元素。 所以有了这个输入:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<CHILD>A</CHILD>
<CHILDBEZ>ABEZ</CHILDBEZ>
<NotInteresting></NotInteresting>
</MyElement>
<MyElement>
<CHILD>B</CHILD>
<CHILDBEZ>BBEZ</CHILDBEZ>
<NotInteresting2></NotInteresting2>
</MyElement>
</TEST>
所需的输出:
<TEST>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>
到目前为止我有什么(基于这个解决方案
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:param name="mapping" select="document('mapping.xml')"/>
<xsl:key name="map" match="*" use="."/>
<xsl:template match="/">
<xsl:variable name="first-pass">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$first-pass/*"/>
</xsl:template>
<xsl:template match="*" mode="first-pass">
<xsl:param name="parent-path" tunnel="yes"/>
<xsl:variable name="path" select="concat($parent-path, '/', name())"/>
<xsl:variable name="replacement" select="key('map', $path, $mapping)"/>
<xsl:variable name="condition" select="key('map', $path, $mapping)/@condition"/>
<xsl:choose>
<xsl:when test="$condition!= ''">
<!-- if there is a condition defined in the mapping file, check for it -->
</xsl:when>
<xsl:otherwise>
<xsl:element name="{if ($replacement) then name($replacement) else name()}">
<xsl:attribute name="original" select="not($replacement)"/>
<xsl:apply-templates mode="first-pass">
<xsl:with-param name="parent-path" select="$path" tunnel="yes"/>
</xsl:apply-templates>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@original='true' and not(descendant::*/@original='false')]"/>
</xsl:stylesheet>
但问题是无法使用 XSLT 2.0 评估动态 XPATH 表达式。有谁知道解决方法吗?另外我的映射文件有问题。当其中只有一个元素时,它根本不起作用。
如果动态 XPath 评估不是您所选处理器的一个选项,那么生成 XSLT 样式表通常是一个不错的选择。事实上,它通常是一个不错的选择。
一种思考方式是,您的映射文件实际上是一个用非常简单的转换语言编写的程序。有两种执行该程序的方法:您可以编写一个解释器(动态 XPath 评估),或者您可以编写一个编译器(XSLT 样式表生成)。两者都很好。