根据xslt中子节点中元素的值重命名并发送所有子节点

时间:2014-11-22 12:28:22

标签: xml xslt

我的意见是:

    <Recordset>
      <Report_ID>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>a1</name2>
          <name3>a1</name3>
          <name4>true</name4>
        </Record>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>b1</name2>
          <name3>t1</name3>
          <name4>false</name4>
        </Record>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>a1</name2>
          <name3>a1</name3>
          <name4>false</name4>
        </Record>
   </Report_ID>
   <Report_ID>
      <Record>
        <Report_ID>B1</Report_ID>
        <name1>a1</name1>
        <name2>a1</name2>
        <name3>a1</name3>
        <name4>true</name4>
    </Record>
    <Record>
        <Report_ID>B1</Report_ID>
        <name1>a1</name1>
        <name2>a1</name2>
        <name3>a1</name3>
        <name4>true</name4>
    </Record>
  </Report_ID>
</Recordset>

最初,我在一个Report_Id下有多条记录,我按唯一报告_Id进行了分组。接下来我想实现以下目标:

目标:如果在一个Report_ID中,name4中的任何一个为“false”,则该Report_Id下的所有记录都应该去,并且父节点应该重命名为Report_ID_Complicated,如果所有name4值都为true,则应将其重命名为Report_ID_Simple。分组很好......必须有另一个检查条件,并相应地重命名父节点。

<Recordset>
      <Report_ID_Complicated>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>a1</name2>
          <name3>a1</name3>
          <name4>true</name4>
        </Record>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>b1</name2>
          <name3>t1</name3>
          <name4>false</name4>
        </Record>
        <Record>
          <Report_ID>A1</Report_ID>
          <name1>a1</name1>
          <name2>a1</name2>
          <name3>a1</name3>
          <name4>false</name4>
        </Record>
   </Report_ID_Complicated>
   <Report_ID_Simple>
      <Record>
        <Report_ID>B1</Report_ID>
        <name1>a1</name1>
        <name2>a1</name2>
        <name3>a1</name3>
        <name4>true</name4>
    </Record>
    <Record>
        <Report_ID>B1</Report_ID>
        <name1>a1</name1>
        <name2>a1</name2>
        <name3>a1</name3>
        <name4>true</name4>
    </Record>
  </Report_ID_Simple>
</Recordset>

更新

Tim的回答是完美的,但是当我尝试将Tim的答案与我之前的代码合并时,我已经编写了下面的代码来对报告ID进行分组“得到”xstl for-each元素必须不包含xsl:template元素“

我相信我们不能在每个内部应用模板,所以如果你能指出我如何合并两个代码的正确方向将会有很大的帮助。

我的Xslt代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kReport_Id" match="Record" use="Report_Id"/>
<xsl:key name="kname4" match="Record" use="concat(Report_Id,name4)"/>
<xsl:template match="/">
    <ns:File_Intermediate>
        <xsl:for-each select="ns:File/RecordSet/Record[generate-id() = generate-id(key('kReport_Id',Report_Id))]">
            <Report_Id>
                <ReportID_Simple>
                    <xsl:variable name="vReport_Id" select="Report_Id"/>
                    <xsl:for-each select="../Record[Report_Id = $vReport_Id][generate-id() = generate-id(key('kname4',concat(Report_Id,name4)))]">
                        <xsl:for-each select="../Record[Report_Id = $vReport_Id][name4=current()/name4]">
                            <xsl:variable name="name4" select="name4"/>
                            <xsl:if test="name4='true'">
                                <xsl:copy-of select="."/>
                            </xsl:if>
                        </xsl:for-each>
                    </xsl:for-each>
                </ReportID_Simple>
                <ReportID_Complicated>
                    <xsl:variable name="vReport_Id" select="Report_Id"/>
                    <xsl:for-each select="../Record[Report_Id = $vReport_Id][generate-id() = generate-id(key('kname4',concat(Report_Id,name4)))]">
                        <xsl:for-each select="../Record[Report_Id = $vReport_Id][name4=current()/name4]">
                            <xsl:variable name="name4" select="name4"/>
                            <xsl:if test="name4='false'">
                                <xsl:copy-of select="."/>
                            </xsl:if>
                        </xsl:for-each>
                    </xsl:for-each>
                </ReportID_Complicated>
            </Report_Id>
        </xsl:for-each>
    </ns:File_Intermediate>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:2)

首先需要从XSLT identity template开始,它自己复制XML中的所有节点

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

这意味着您只需要为要转换的节点编写模板。您希望将Report_ID个元素更改为Report_ID_Complicated,其中Record的{​​{1}}为name4。这意味着您只需要一个模板来匹配这样的记录

<xsl:template match="Recordset/Report_ID[Record/name4 = 'false']">

请注意使用前面的Recordset,因为XML中嵌套了Report_ID

除了您可以显式创建新节点而不是复制现有节点

之外,内容与身份模板类似。
   <Report_ID_Complicated>
      <xsl:apply-templates select="@*|node()"/>
   </Report_ID_Complicated>

对于另一个模板,您可以匹配相反的:

<xsl:template match="Recordset/Report_ID[not(Record/name4 = 'false')]">

请注意,编写第二个这样的模板是不正确的。

<xsl:template match="Recordset/Report_ID">

这是因为XSLT认为它具有与前一个相同的优先级,这是一个错误,因此您需要额外的xpath条件来区分它。另外,请注意,如果您有一个匹配此模板的模板......

<xsl:template match="Report_ID">

这将具有较低的优先级,这是可以接受的,但是对于您的XML,您有嵌套的Report_ID元素,它也会匹配(感谢Lingamurthy CS指出这一点!)

试试这个XSLT

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

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

   <xsl:template match="Recordset/Report_ID[Record/name4 = 'false']">
      <Report_ID_Complicated>
         <xsl:apply-templates select="@*|node()"/>
      </Report_ID_Complicated>
   </xsl:template>   

   <xsl:template match="Recordset/Report_ID[not(Record/name4 = 'false')]">
      <Report_ID_Simple>
         <xsl:apply-templates select="@*|node()"/>
      </Report_ID_Simple>
   </xsl:template>
</xsl:stylesheet>