递归属性计算?
recursive attribute calculation?
XML 输入:
<a>
<desc key="1" attr1="# {@key}" attr2="{@key} #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="{@key}" title="{@attr4}+{@attr4}" >
<val key="3">
<fix key="4" title11="{@key} {@key}" title="{@key}+{@title11}" >
<c></c>
</fix>
</val>
<numb key="5" title12="z{@key}z in {@key}" title="{@title12}+{@key}" titlew="{@title}+{@title12}">
</numb>
</slot>
</b>
</desc>
</a>
我有这个 XML 转换代码 XSLT1.0:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="*/@*">
<xsl:attribute name="{name()}">
<xsl:call-template name="replace">
<xsl:with-param name="str" select="."/>
<xsl:with-param name="find" select="'{@key}'"/>
<xsl:with-param name="replace" select="../@key"/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<!--Identity template-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="str"/>
<xsl:param name="find"/>
<xsl:param name="replace"/>
<xsl:choose>
<xsl:when test="contains($str, $find)">
<xsl:variable name="prefix" select="substring-before($str, $find)"/>
<xsl:variable name="suffix">
<xsl:call-template name="replace">
<xsl:with-param name="str" select="substring-after($str, $find)"/>
<xsl:with-param name="find" select="$find"/>
<xsl:with-param name="replace" select="$replace"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($prefix, $replace, $suffix)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
此代码查找标签属性值中出现的任何“{@key}”。如果标记在“@”字符后指定了属性,即在本例中为 'key',则字符串“{@key}”将替换为 'key' 属性的值。那么转换后的XML文件会是这样的:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="2" title="{@attr4}+{@attr4}">
<val key="3">
<fix key="4" title11="4 4" title="4+{@title11}">
<c />
</fix>
</val>
<numb key="5" title12="z5z in 5" title="{@title12}+5" titlew="{@title}+{@title12}">
</numb>
</slot>
</b>
</desc>
</a>
但我不仅需要用 'key' 属性的值替换字符串 '{@key}',而且还需要一个更通用的规则:如果标签具有属性 'attr',然后值标记属性中出现的任何字符串“{@attr}”都被替换为 'attr' 属性的值。有没有办法使用 XSLT 1.0 执行此操作,以便在转换后 XML 文件如下所示:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="2" title="2+2" >
<val key="3">
<fix key="4" title11="4 4" title="4+4 4" >
<c></c>
</fix>
</val>
<numb key="5" title12="z5z in 5" title="z5z in 5+5" titlew="z5z in 5+5+z5z in 5">
</numb>
</slot>
</b>
</desc>
</a>
如果可以假设一个属性永远不会包含 {}
个字符,而不是包含对同一父元素的另一个属性的引用,那么您可以这样做:
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:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:call-template name="expand">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template name="expand">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '{') ">
<!-- text before reference -->
<xsl:value-of select="substring-before($text, '{')"/>
<!-- recursive call with the expanded reference-->
<xsl:variable name="name" select="substring-before(substring-after($text, '{@'), '}')" />
<xsl:call-template name="expand">
<xsl:with-param name="text" select="../@*[name()=$name]"/>
</xsl:call-template>
<!-- recursive call with rest of the text -->
<xsl:call-template name="expand">
<xsl:with-param name="text" select="substring-after($text, '}')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
注意:没有经过非常彻底的测试。
XML 输入:
<a>
<desc key="1" attr1="# {@key}" attr2="{@key} #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="{@key}" title="{@attr4}+{@attr4}" >
<val key="3">
<fix key="4" title11="{@key} {@key}" title="{@key}+{@title11}" >
<c></c>
</fix>
</val>
<numb key="5" title12="z{@key}z in {@key}" title="{@title12}+{@key}" titlew="{@title}+{@title12}">
</numb>
</slot>
</b>
</desc>
</a>
我有这个 XML 转换代码 XSLT1.0:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="*/@*">
<xsl:attribute name="{name()}">
<xsl:call-template name="replace">
<xsl:with-param name="str" select="."/>
<xsl:with-param name="find" select="'{@key}'"/>
<xsl:with-param name="replace" select="../@key"/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<!--Identity template-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="str"/>
<xsl:param name="find"/>
<xsl:param name="replace"/>
<xsl:choose>
<xsl:when test="contains($str, $find)">
<xsl:variable name="prefix" select="substring-before($str, $find)"/>
<xsl:variable name="suffix">
<xsl:call-template name="replace">
<xsl:with-param name="str" select="substring-after($str, $find)"/>
<xsl:with-param name="find" select="$find"/>
<xsl:with-param name="replace" select="$replace"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($prefix, $replace, $suffix)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
此代码查找标签属性值中出现的任何“{@key}”。如果标记在“@”字符后指定了属性,即在本例中为 'key',则字符串“{@key}”将替换为 'key' 属性的值。那么转换后的XML文件会是这样的:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="2" title="{@attr4}+{@attr4}">
<val key="3">
<fix key="4" title11="4 4" title="4+{@title11}">
<c />
</fix>
</val>
<numb key="5" title12="z5z in 5" title="{@title12}+5" titlew="{@title}+{@title12}">
</numb>
</slot>
</b>
</desc>
</a>
但我不仅需要用 'key' 属性的值替换字符串 '{@key}',而且还需要一个更通用的规则:如果标签具有属性 'attr',然后值标记属性中出现的任何字符串“{@attr}”都被替换为 'attr' 属性的值。有没有办法使用 XSLT 1.0 执行此操作,以便在转换后 XML 文件如下所示:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="2" title="2+2" >
<val key="3">
<fix key="4" title11="4 4" title="4+4 4" >
<c></c>
</fix>
</val>
<numb key="5" title12="z5z in 5" title="z5z in 5+5" titlew="z5z in 5+5+z5z in 5">
</numb>
</slot>
</b>
</desc>
</a>
如果可以假设一个属性永远不会包含 {}
个字符,而不是包含对同一父元素的另一个属性的引用,那么您可以这样做:
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:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:call-template name="expand">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template name="expand">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '{') ">
<!-- text before reference -->
<xsl:value-of select="substring-before($text, '{')"/>
<!-- recursive call with the expanded reference-->
<xsl:variable name="name" select="substring-before(substring-after($text, '{@'), '}')" />
<xsl:call-template name="expand">
<xsl:with-param name="text" select="../@*[name()=$name]"/>
</xsl:call-template>
<!-- recursive call with rest of the text -->
<xsl:call-template name="expand">
<xsl:with-param name="text" select="substring-after($text, '}')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
注意:没有经过非常彻底的测试。