给出以下XML:
<root>
<group>
<e1>001</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>002</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>003</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>004</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
请注意,每个“ group”元素中的“ e2”元素都相同,这在源文档中得到保证。
我正在尝试使用XSLT执行以下步骤:
所需的输出如下所示:
<root>
<group>
<e1>default1</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>default2</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
源文档中的'e1'值无关紧要,并且输出文档中的'e2'值是预先已知的并且是静态的。只是'e2'值是动态的,我需要确保它们都在其中。
在用一些硬编码的值替换所有元素之前,我曾使用过类似的模式:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!-- Empty Template eliminates all but first 'group' element. -->
<xsl:template match="//group[preceding::group]"></xsl:template>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
<xsl:element name="group">
<e1>default2</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
</xsl:template>
我尝试将这些元素存储到变量中,但未将任何内容插入到输出html中:
<xsl:variable name="e2Elements" select="//group[1]/e2"></xsl:variable>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<xsl:copy-of select="$e2Elements" />
</xsl:element>
</xsl:template>
但是不确定如何将e2元素插入值中。我正在使用SaxonHE9.8N并可以访问exslt命名空间和xslt2.0
答案 0 :(得分:2)
您的解决方案实际上是不必要地复制了元素。您可以不复制它们而这样做,就像这样:
<xsl:variable name="e3Elements" select="//group[1]/e2" />
另一个效率低下的问题是<xsl:template match="group[preceding::group]"/>
使用前一个轴总是很昂贵,但是在模式中尤其如此。明显的改进是将其替换为先前的同级(搜索先前的同级轴比搜索先前的同级轴要快得多)。但是实际上,您可以做得更好:将其设置为组(<xsl:template match="group"/>
)的默认规则,并使另一个规则仅与第一个组(<xsl:template match="group[1]">...
)匹配。
但是实际上,也不需要匹配第一个group元素,因为您没有使用它的任何数据。
从风格上讲,<group>
比<xsl:element name="group">
更受青睐,仅仅是因为它更具可读性。
这将是我的XSLT 3.0解决方案:
<xsl:transform version="3.0" .... expand-text="yes">
<xsl:template match="/">
<xsl:variable name="e3Elements" select="//group[1]/e2"/>
<xsl:for-each select="'default1', 'default2'">
<group>
<e1>{.}</e1>
<xsl:copy-of select="$e3Elements"/>
</group>
</xsl:for-each>
</xsl:template>
</xsl:transform>
答案 1 :(得分:1)
请记住,我需要使用copy-of使变量成为元素的副本。以下是我的解决方案:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="e3Elements">
<xsl:copy-of select="//group[1]/e2" />
</xsl:variable>
<xsl:template match="group[preceding::group]"></xsl:template>
<xsl:template match="group">
<xsl:element name="group">
<xsl:element name="e1">default1</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
<xsl:element name="group">
<xsl:element name="e1">default2</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
</xsl:template>