选择元素,其名称等于属性的值

时间:2017-01-14 21:24:23

标签: xslt xpath

我有一个输入XML,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Rules>
        <Rule ruleName="Rule1" ruleType="A"/>
        <Rule ruleName="Rule2" ruleType="B"/>
        <Rule ruleName="Rule3" ruleType="C"/>
    </Rules>
    <Description>
        <Rule1>My description for rule 1</Rule1>
        <Rule2>My description for rule 2</Rule2>
        <Rule3>My description for rule 3</Rule3>
    </Description>
</Root>

我需要通过XSLT将其转换为如下结构:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Rules>
        <Rule ruleName="Rule1" ruleType="A"/>
            <Description>My description for rule 1</Description>
        </Rule>
        <Rule ruleName="Rule2" ruleType="B"/>         
            <Description>My description for rule 2</Description>
        </Rule>
        <Rule ruleName="Rule3" ruleType="C">
            <Description>My description for rule 3</Description>
        </Rule>
    </Rules>
</Root>

这意味着对于每个 / Root / Rules / Rule 节点,我必须根据< / Root / Description / Rule?节点选择值< em> / Root / Rules / Rule / @ ruleName 值。 / Root / Rules / Rule / Root / Description / Rule?的顺序是随机的。

我已经创建了一个模板来处理 / Root / Rules / Rule 节点,但我无法弄清楚如何编写一个xpath,因为“从 / Root中选择节点值/ Description 其中节点名称等于 ./@ ruleName 。我有什么想法或程序可以实现它吗?

2 个答案:

答案 0 :(得分:2)

使用name="ref" match="Description/*" use="local-name()"定义密钥,然后您可以使用key('ref', @ruleName)查找Description元素。请参阅https://www.w3.org/TR/xslt#key

作为替代方案,您可以使用current()https://www.w3.org/TR/xslt#function-current)来编写相对于当前匹配节点的XPath表达式,即使用

<xsl:template match="/Root/Rules/Rule">
   <xsl:copy>
      <xsl:copy-of select="@*"/>
      <Description>
         <xsl:value-of select="/Root/Description/*[local-name() = current()/@ruleName]"/>
      </Description>
   </xsl:copy>
</xsl:template>

您获得与密钥相同的结果。考虑阅读密钥,然而,在XSLT中有效地遵循交叉引用是一个基本概念。

答案 1 :(得分:2)

虽然我更喜欢Martin的解决方案,但请参阅以下解决方案,将规则名称存储在变量中,然后在XPath表达式中使用它:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
  <xsl:apply-templates select = "Root/Rules/*"/>
</xsl:template>

<xsl:template match="Rule">
 <xsl:variable name="rulename" select="@ruleName"/>
   <xsl:element name="Rule">
     <xsl:copy-of select="@*"/>
     <xsl:element name="Description">
       <xsl:copy-of select="/Root/Description/*[local-name() = $rulename]/text()"/>
     </xsl:element>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>