XSL:转义 CDATA 并在内部使用 for-each 解析为 xml
XSL: escaping CDATA and parse as xml inside with for-each
我有一个 xml 文档(无法更改输入文件),我需要用 xsl 将其转换为另一个 xml。输入 xsl 有一个 CDATA,如以下示例结构所示:
<TestCaseElement>
<Role>VP</Role>
<Code>
<Line>
<![CDATA[<id>l1_SomeId1</id> <val1>l1_SomeVal1</val1> <val2>l1_SomeVal2</val2> <algo>l1_somealgo</algo>]]>
</Line>
<Line>
<![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]>
</Line>
</Code>
<TestCaseElement>
预期结果类似于:
<Expected>
<MEASV id="l1_SomeId1" val1="l1_SomeVal1" val2="l1_SomeVal2" algo="l1_somealgo">
<MEASV id="l2_SomeId1" val1="l2_SomeVal1" val2="l2_SomeVal2" algo="l2_somealgo">
</Expected>
我的 Xslt 看起来像:
<Expected>
<xsl:for-each select="TestCaseElement[(Role='VP')]/Code/Line">
<xsl:for-each select="current()/*">
<MEASV>
<xsl:attribute name="{fn:local-name()}"><xsl:value-of select="current()"/></xsl:attribute>
</MEASV>
</xsl:for-each>
</xsl:for-each>
</Expected>
问题是 xslt 无法识别 CDATA 中的标签。我如何为每个应用一种禁用输出转义?或者有什么其他方法可以解决这个问题?
考虑使用 XSLT 3.0(受 Saxon 9.8 和 Altova XMLSpy/Raptor 支持)和 parse-xml-fragment()
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<Expected>
<xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
</Expected>
</xsl:template>
<xsl:template match="Line">
<MEASV>
<xsl:apply-templates select="parse-xml-fragment(.)/*"/>
</MEASV>
</xsl:template>
<xsl:template match="*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:template>
</xsl:stylesheet>
请注意,在您发布的示例中,一个转义标记 <![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]>
包含格式错误的标记,其中 val1
和 val2
未正确关闭,因此上述代码对于该输入将失败,或者您需要使用 try/catch
捕获任何解析错误:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="xs math err"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<Expected>
<xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
</Expected>
</xsl:template>
<xsl:template match="Line">
<MEASV>
<xsl:try>
<xsl:apply-templates select="parse-xml-fragment(.)/*"/>
<xsl:catch errors="err:FODC0006">
<xsl:message select="'Error parsing', ."/>
</xsl:catch>
</xsl:try>
</MEASV>
</xsl:template>
<xsl:template match="*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:template>
</xsl:stylesheet>
我有一个 xml 文档(无法更改输入文件),我需要用 xsl 将其转换为另一个 xml。输入 xsl 有一个 CDATA,如以下示例结构所示:
<TestCaseElement>
<Role>VP</Role>
<Code>
<Line>
<![CDATA[<id>l1_SomeId1</id> <val1>l1_SomeVal1</val1> <val2>l1_SomeVal2</val2> <algo>l1_somealgo</algo>]]>
</Line>
<Line>
<![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]>
</Line>
</Code>
<TestCaseElement>
预期结果类似于:
<Expected>
<MEASV id="l1_SomeId1" val1="l1_SomeVal1" val2="l1_SomeVal2" algo="l1_somealgo">
<MEASV id="l2_SomeId1" val1="l2_SomeVal1" val2="l2_SomeVal2" algo="l2_somealgo">
</Expected>
我的 Xslt 看起来像:
<Expected>
<xsl:for-each select="TestCaseElement[(Role='VP')]/Code/Line">
<xsl:for-each select="current()/*">
<MEASV>
<xsl:attribute name="{fn:local-name()}"><xsl:value-of select="current()"/></xsl:attribute>
</MEASV>
</xsl:for-each>
</xsl:for-each>
</Expected>
问题是 xslt 无法识别 CDATA 中的标签。我如何为每个应用一种禁用输出转义?或者有什么其他方法可以解决这个问题?
考虑使用 XSLT 3.0(受 Saxon 9.8 和 Altova XMLSpy/Raptor 支持)和 parse-xml-fragment()
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<Expected>
<xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
</Expected>
</xsl:template>
<xsl:template match="Line">
<MEASV>
<xsl:apply-templates select="parse-xml-fragment(.)/*"/>
</MEASV>
</xsl:template>
<xsl:template match="*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:template>
</xsl:stylesheet>
请注意,在您发布的示例中,一个转义标记 <![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]>
包含格式错误的标记,其中 val1
和 val2
未正确关闭,因此上述代码对于该输入将失败,或者您需要使用 try/catch
捕获任何解析错误:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="xs math err"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<Expected>
<xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
</Expected>
</xsl:template>
<xsl:template match="Line">
<MEASV>
<xsl:try>
<xsl:apply-templates select="parse-xml-fragment(.)/*"/>
<xsl:catch errors="err:FODC0006">
<xsl:message select="'Error parsing', ."/>
</xsl:catch>
</xsl:try>
</MEASV>
</xsl:template>
<xsl:template match="*">
<xsl:attribute name="{local-name()}" select="."/>
</xsl:template>
</xsl:stylesheet>