XSLT / XPath替换特定节点

时间:2013-01-16 21:37:42

标签: xml xslt xpath

我有以下xml数据结构要转换:

<root>
        <main1>
            <page>
                <text-body>
                    <title>K1</title>
                    <subtitle>Text</subtitle>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
            <page>
                <text-body>
                    <title>K2</title>
                    <subtitel>Text</subtitel>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
            <page>
                <text-body>
                    <title>K3</title>
                    <subtitel>Text</subtitel>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
        </main1>
        <main2>
            <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body>
            <text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body>
            <text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>
        </main2>
 </root>

我需要将main1 / text-body中的数据替换为标题K1,K2,K3和main2 / text-body中的数据,但是将其他text-body元素保留在main1中。输出应如下所示:

<root>
        <main1>
            <page>
                <text-body>
                    <title>B</title>
                    <subtitle>B</subtitle>
                    <body>B</body>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
            <page>
                <text-body>
                    <title>C</title>
                    <subtitle>C</subtitle>
                    <body>C</body>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
            <page>
                <text-body>
                    <title>D</title>
                    <subtitle>D</subtitle>
                    <body>D</body>
                </text-body>
                <text-body>
                    <title>Text</title>
                    <subtitel>Text</subtitel>
                </text-body>
            </page>
        </main1>
        <main2>
            <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body>
            <text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body>
            <text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>
        </main2>
 </root>

我有以下xsl代码:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml"/>

       <xsl:template match="@*|node()">
        <xsl:copy>
             <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
       </xsl:template>

        <xsl:template match="main1/page/text-body">
            <xsl:param name="count" select="title/substring(.,2,1)"/>
            <xsl:if test="title/substring(.,1,1)='K'">
               <xsl:copy-of select="/root/main2/text-body[$count]"/>
            </xsl:if>
        </xsl:template>

    </xsl:stylesheet>

我尝试选择标题中的数字,并检查文本中是否有K.但它不起作用。我不知道如何保留其他文本正文元素。这是当前的输出:

 <main1>
            <page>
                <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body><text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body><text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>


            </page>
            <page>
                <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body><text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body><text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>

            </page>
            <page>
                <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body><text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body><text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>

            </page>
        </main1>
        <main2>
            <text-body>
                <title>B</title>
                <subtitle>B</subtitle>
                <body>B</body>
            </text-body>
            <text-body>
                <title>C</title>
                <subtitle>C</subtitle>
                <body>C</body>
            </text-body>
            <text-body>
                <title>D</title>
                <subtitle>D</subtitle>
                <body>D</body>
            </text-body>
        </main2>
 </root>

请帮忙!

2 个答案:

答案 0 :(得分:0)

使用谓词仅匹配您真正想要交换的text-body元素。在使用XSLT 2.0时,可以在谓词中使用正则表达式:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="main1/page/text-body[matches(title,'^K\d+$')]">
    <xsl:variable name="count" select="xs:integer(title/substring(.,2))"/>
    <xsl:copy-of select="/root/main2/text-body[$count]"/>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

主要问题是您的 count 参数设置为字符串,但如果您想将in用作索引,则它应该是一个数字,因此您需要执行此操作< / p>

<xsl:copy-of select="/root/main2/text-body[number($count)]"/>

此外,您可能不希望在此使用 xsl:if ,因为使用当前模板时,如果使用if,则不会输出 text-body 元素条件是假的。您实际应该将测试移动到模板匹配的一部分。

<xsl:template match="main1/page/text-body[title/substring(.,1,1)='K']">

这是完整的XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="xml"/>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="main1/page/text-body[title/substring(.,1,1)='K']">
      <xsl:param name="count" select="title/substring(.,2,1)"/>
      <xsl:copy-of select="/root/main2/text-body[number($count)]"/>
   </xsl:template>
</xsl:stylesheet>

这应该会产生您的预期输出。

如果您对不同的方法感兴趣,可以选择定义 xsl:key 来查找 main2 / text-body 元素

<xsl:key name="main2" 
     match="main2/text-body" 
     use="concat('K', count(preceding-sibling::text-body) + 1)" />

这样,您可以通过使用以下模板来匹配 main1 / page / text-body 元素来删除对子字符串的需求

 <xsl:template match="main1/page/text-body[key('main2', title)]">
    <xsl:copy-of select="key('main2', title)"/>
 </xsl:template>