属性值的 xpath 部分?
xpath part of attribute value?
输入xml文件:
<a>
<desc key="1" attr1="# {@key}" attr2="{@key} #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="xf{../../../@key}" title="{../../../@key}gk+{../../../@key}" >
<val key="3">
<fix key="4" title11="{@key} {../@key}" title="{../../@key}+{@title11}" >
<c attr4="{../../@key} and 1" attr5 = "{@attr4} or {../@key}" />
</fix>
</val>
<numb key="5" title12="z{@key}z in {../@key}" title="{@title12}+{slot/val/@key}" titlew="{@title}+{fix/@title}" />
</slot>
</b>
</desc>
</a>
大括号指示属性的 XPath,而不是您必须沿此 XPath 替换属性的值,例如,
代替 {@key} 和 {../@key},替换当前节点的 key 属性的值。 XSLT1.0 转换后的文件应该是这样的:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="xf1" title="1gk+1" >
<val key="3">
<fix key="4" title11="4 4" title="3+4" >
<c attr4="4 and 1" attr5 = "4 and 1 or ">
</fix>
</val>
<numb key="5" title12="z5z in 5" title="z5z in 5+3" titlew="z5z in 5+3+3+4" />
</slot>
</b>
</desc>
</a>
现在这是 XSLT1.0 转换文件:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="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, '{') ">
<xsl:value-of select="substring-before($text, '{')"/>
<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>
<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="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="xf" title="gk+">
<val key="3">
<fix key="4" title11="4 " title="4 +4 ">
<c attr4=" and 1" attr5=" and 1 or " />
</fix>
</val>
<numb key="5" title12="z5z in " title="z5z in +" titlew="z5z in ++" />
</slot>
</b>
</desc>
</a>
如何正确生成属性值的 xpath 部分?
如前所述,您需要 XSLT 3 中的 xsl:evaluate
或 XSLT 2 或 1 的类似扩展;此外,您需要找到要评估的 {...}
个“模板”,并且仅当引用的属性值已被计算时,您才需要实施一个评估“模板”的策略。
使用 XSLT 3 我达到了:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns:mf="http://example.com/mf"
version="3.0">
<xsl:param name="avt-pattern" as="xs:string" expand-text="no">\{(.*?)\}</xsl:param>
<xsl:mode name="convert" on-no-match="shallow-copy"/>
<xsl:template mode="convert" match="@*[matches(., $avt-pattern)]">
<xsl:variable name="context" select=".."/>
<xsl:attribute name="{name()}">
<xsl:analyze-string select="." regex="{$avt-pattern}">
<xsl:matching-substring>
<xsl:variable name="evaluated-result" as="xs:string">
<xsl:evaluate xpath="regex-group(1)" context-item="$context"/>
</xsl:variable>
<xsl:value-of select="if (matches($evaluated-result, $avt-pattern)) then . else $evaluated-result"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:attribute>
</xsl:template>
<xsl:function name="mf:evaluate-attributes" as="document-node()">
<xsl:param name="input" as="node()"/>
<xsl:variable name="result" as="node()">
<xsl:apply-templates select="$input" mode="convert"/>
</xsl:variable>
<xsl:sequence
select="if ($result//@*[matches(., $avt-pattern)])
then mf:evaluate-attributes($result)
else $result"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="mf:evaluate-attributes(.)"/>
</xsl:template>
</xsl:stylesheet>
在线示例 https://xsltfiddle.liberty-development.net/jy6KM8D。
使用 XSLT 1.0 和 Microsoft 可以在项目 https://www.nuget.org/packages/Mvp.Xml.NetStandard 的帮助下完成此操作,然后
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt regexp dyn2 mf"
xmlns:mf="http://example.com/mf"
xmlns:regexp="http://exslt.org/regular-expressions"
xmlns:dyn2="http://gotdotnet.com/exslt/dynamic"
version="1.0">
<xsl:param name="avt-pattern">\{(.*?)\}</xsl:param>
<xsl:template mode="convert" match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="convert"/>
</xsl:copy>
</xsl:template>
<xsl:template name="evaluate-avts">
<xsl:param name="attribute-value"/>
<xsl:param name="context"/>
<xsl:choose>
<xsl:when test="contains($attribute-value, '{')">
<xsl:value-of select="substring-before($attribute-value, '{')"/>
<xsl:variable name="remainder" select="substring-after($attribute-value, '{')"/>
<xsl:variable name="avt" select="substring-before($remainder, '}')"/>
<xsl:call-template name="evaluate-avt">
<xsl:with-param name="expression" select="$avt"/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
<xsl:call-template name="evaluate-avts">
<xsl:with-param name="attribute-value" select="substring-after($remainder, '}')"/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$attribute-value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="evaluate-avt">
<xsl:param name="expression"/>
<xsl:param name="context"/>
<xsl:variable name="evaluated-result" select="dyn2:evaluate($context, $expression)"/>
<xsl:choose>
<xsl:when test="regexp:test($evaluated-result, $avt-pattern)">
<xsl:value-of select="concat('{', $expression, '}')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$evaluated-result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template mode="convert" match="@*">
<xsl:choose>
<xsl:when test="regexp:test(., $avt-pattern)">
<xsl:variable name="context" select=".."/>
<xsl:attribute name="{name()}">
<xsl:call-template name="evaluate-avts">
<xsl:with-param name="attribute-value" select="."/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template mode="evaluate-attributes" match="/">
<xsl:variable name="result-rtf">
<xsl:apply-templates select="." mode="convert"/>
</xsl:variable>
<xsl:variable name="result" select="exslt:node-set($result-rtf)"/>
<xsl:choose>
<xsl:when test="$result//@*[regexp:test(., $avt-pattern)]">
<xsl:apply-templates select="$result" mode="evaluate-attributes"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="." mode="evaluate-attributes"/>
</xsl:template>
</xsl:stylesheet>
输入xml文件:
<a>
<desc key="1" attr1="# {@key}" attr2="{@key} #" attr3="" title="{@attr2}">
<b>
<slot key="2" attr4="xf{../../../@key}" title="{../../../@key}gk+{../../../@key}" >
<val key="3">
<fix key="4" title11="{@key} {../@key}" title="{../../@key}+{@title11}" >
<c attr4="{../../@key} and 1" attr5 = "{@attr4} or {../@key}" />
</fix>
</val>
<numb key="5" title12="z{@key}z in {../@key}" title="{@title12}+{slot/val/@key}" titlew="{@title}+{fix/@title}" />
</slot>
</b>
</desc>
</a>
大括号指示属性的 XPath,而不是您必须沿此 XPath 替换属性的值,例如, 代替 {@key} 和 {../@key},替换当前节点的 key 属性的值。 XSLT1.0 转换后的文件应该是这样的:
<a>
<desc key="1" attr1="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="xf1" title="1gk+1" >
<val key="3">
<fix key="4" title11="4 4" title="3+4" >
<c attr4="4 and 1" attr5 = "4 and 1 or ">
</fix>
</val>
<numb key="5" title12="z5z in 5" title="z5z in 5+3" titlew="z5z in 5+3+3+4" />
</slot>
</b>
</desc>
</a>
现在这是 XSLT1.0 转换文件:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="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, '{') ">
<xsl:value-of select="substring-before($text, '{')"/>
<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>
<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="# 1" attr2="1 #" attr3="" title="1 #">
<b>
<slot key="2" attr4="xf" title="gk+">
<val key="3">
<fix key="4" title11="4 " title="4 +4 ">
<c attr4=" and 1" attr5=" and 1 or " />
</fix>
</val>
<numb key="5" title12="z5z in " title="z5z in +" titlew="z5z in ++" />
</slot>
</b>
</desc>
</a>
如何正确生成属性值的 xpath 部分?
如前所述,您需要 XSLT 3 中的 xsl:evaluate
或 XSLT 2 或 1 的类似扩展;此外,您需要找到要评估的 {...}
个“模板”,并且仅当引用的属性值已被计算时,您才需要实施一个评估“模板”的策略。
使用 XSLT 3 我达到了:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns:mf="http://example.com/mf"
version="3.0">
<xsl:param name="avt-pattern" as="xs:string" expand-text="no">\{(.*?)\}</xsl:param>
<xsl:mode name="convert" on-no-match="shallow-copy"/>
<xsl:template mode="convert" match="@*[matches(., $avt-pattern)]">
<xsl:variable name="context" select=".."/>
<xsl:attribute name="{name()}">
<xsl:analyze-string select="." regex="{$avt-pattern}">
<xsl:matching-substring>
<xsl:variable name="evaluated-result" as="xs:string">
<xsl:evaluate xpath="regex-group(1)" context-item="$context"/>
</xsl:variable>
<xsl:value-of select="if (matches($evaluated-result, $avt-pattern)) then . else $evaluated-result"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:attribute>
</xsl:template>
<xsl:function name="mf:evaluate-attributes" as="document-node()">
<xsl:param name="input" as="node()"/>
<xsl:variable name="result" as="node()">
<xsl:apply-templates select="$input" mode="convert"/>
</xsl:variable>
<xsl:sequence
select="if ($result//@*[matches(., $avt-pattern)])
then mf:evaluate-attributes($result)
else $result"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="mf:evaluate-attributes(.)"/>
</xsl:template>
</xsl:stylesheet>
在线示例 https://xsltfiddle.liberty-development.net/jy6KM8D。
使用 XSLT 1.0 和 Microsoft 可以在项目 https://www.nuget.org/packages/Mvp.Xml.NetStandard 的帮助下完成此操作,然后
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt regexp dyn2 mf"
xmlns:mf="http://example.com/mf"
xmlns:regexp="http://exslt.org/regular-expressions"
xmlns:dyn2="http://gotdotnet.com/exslt/dynamic"
version="1.0">
<xsl:param name="avt-pattern">\{(.*?)\}</xsl:param>
<xsl:template mode="convert" match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="convert"/>
</xsl:copy>
</xsl:template>
<xsl:template name="evaluate-avts">
<xsl:param name="attribute-value"/>
<xsl:param name="context"/>
<xsl:choose>
<xsl:when test="contains($attribute-value, '{')">
<xsl:value-of select="substring-before($attribute-value, '{')"/>
<xsl:variable name="remainder" select="substring-after($attribute-value, '{')"/>
<xsl:variable name="avt" select="substring-before($remainder, '}')"/>
<xsl:call-template name="evaluate-avt">
<xsl:with-param name="expression" select="$avt"/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
<xsl:call-template name="evaluate-avts">
<xsl:with-param name="attribute-value" select="substring-after($remainder, '}')"/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$attribute-value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="evaluate-avt">
<xsl:param name="expression"/>
<xsl:param name="context"/>
<xsl:variable name="evaluated-result" select="dyn2:evaluate($context, $expression)"/>
<xsl:choose>
<xsl:when test="regexp:test($evaluated-result, $avt-pattern)">
<xsl:value-of select="concat('{', $expression, '}')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$evaluated-result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template mode="convert" match="@*">
<xsl:choose>
<xsl:when test="regexp:test(., $avt-pattern)">
<xsl:variable name="context" select=".."/>
<xsl:attribute name="{name()}">
<xsl:call-template name="evaluate-avts">
<xsl:with-param name="attribute-value" select="."/>
<xsl:with-param name="context" select="$context"/>
</xsl:call-template>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template mode="evaluate-attributes" match="/">
<xsl:variable name="result-rtf">
<xsl:apply-templates select="." mode="convert"/>
</xsl:variable>
<xsl:variable name="result" select="exslt:node-set($result-rtf)"/>
<xsl:choose>
<xsl:when test="$result//@*[regexp:test(., $avt-pattern)]">
<xsl:apply-templates select="$result" mode="evaluate-attributes"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="." mode="evaluate-attributes"/>
</xsl:template>
</xsl:stylesheet>