使用XSLT转换XML文件(组合多个模板)

时间:2013-07-17 09:54:12

标签: xml templates xslt

我现在已经坚持这个问题一段时间了。我有一个样本XML文件,如下所示:

<Records>
 <Record><Id>1</Id><Name>table_id</Name><Attribute></Attribute><Value>1</Value></Record>
 <Record><Id>1</Id><Name>score</Name><Attribute></Attribute><Value>2.1</Value></Record>
 <Record><Id>1</Id><Name>custom4</Name><Attribute>name</Attribute><Value>Custom411</Value></Record>
 <Record><Id>1</Id><Name>custom4</Name><Attribute>name</Attribute><Value>Custom412</Value></Record>
 <Record><Id>2</Id><Name>table_id</Name><Attribute></Attribute><Value>2</Value></Record>
 <Record><Id>2</Id><Name>title</Name><Attribute></Attribute><Value>Title 2</Value></Record>
</Records>

我想使用以下格式的XSLT将所有ID和行合并到另一个XML文件中:

<RECORDS>
 <RECORD>
  <ITEM name="table_id" value="1"/>
  <ITEM name="score" value="2.1"/>
  <LIST name="custom4">
   <LIST_ITEM value="custom411"/>
   <LIST_ITEM value="custom412"/>
  </LIST>
 </RECORD>
 <RECORD>
  <ITEM name="table_id" value="2"/>
  <ITEM name="title" value="Title 2"/>
 </RECORD>
</RECORDS

<table_id> = <Id>的基本价值。因此,对于每个<Id>,我需要创建一个<RECORD>。如果一个<Name>存在多个相同<Id>的值,那么我需要为<name>创建一个LIST_ITEM,否则创建一个正常的ITEM。

到目前为止,我已经能够使用模板基于<Id>对记录进行分组。但我无法使用此模板的输出生成最终输出:

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

<xsl:template match="/">
    <xsl:variable name="output">
        <xsl:call-template name="groupById" />
    </xsl:variable>

    <OBJECTS>
    <xsl:for-each select="$output/Root/Records">
        <OBJECT>
            <xsl:for-each select="Id/Record">
                <ITEM>
                    <xsl:attribute name='name'>
                        <xsl:value-of select="Name" />
                    </xsl:attribute>
                    <xsl:attribute name='value'>
                        <xsl:value-of select="Value" />
                    </xsl:attribute>
                </ITEM>
            </xsl:for-each>
        </OBJECT>
    </xsl:for-each> 
    </OBJECTS>
</xsl:template>

<xsl:template name="groupById">
    <Root>
      <xsl:for-each-group select="/Records/Record" group-by="Id">
      <Records>
        <xsl:for-each-group select="current-group()" group-by="if(Id) then Id else 'no key'">   
            <!-- Copy attributes off the *first* Record element in the group -->
            <xsl:copy-of select="current-group()[1]/Id"/>
            <!-- Copy remaining children from *all* Record elements in the group -->
            <xsl:copy-of select="current-group()"/>
        </xsl:for-each-group>
        </Records>
      </xsl:for-each-group>
    </Root>
</xsl:template>

</xsl:stylesheet>

有人可以从这里引导我或建议其他路线吗?

1 个答案:

答案 0 :(得分:1)

这是一个简短但完整的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"
  exclude-result-prefixes="xs">

<xsl:output method="xml" indent="yes"/>

<xsl:template match="Records">
  <RECORDS>
    <xsl:for-each-group select="Record" group-by="Id">
      <RECORD>
        <ITEM name="table_id" value="{current-grouping-key()}"/>
        <xsl:for-each-group select="current-group()[not(Name = 'table_id')]" group-by="Name">
          <xsl:choose>
            <xsl:when test="current-group()[2]">
              <LIST name="{current-grouping-key()}">
                <xsl:for-each select="current-group()">
                  <LIST_ITEM value="{Value}"/>
                </xsl:for-each>
              </LIST>
            </xsl:when>
            <xsl:otherwise>
              <ITEM name="{Name}" value="{Value}"/>
            </xsl:otherwise>
          </xsl:choose>
         </xsl:for-each-group>
     </RECORD>
   </xsl:for-each-group>
 </RECORDS>
</xsl:template>

</xsl:stylesheet>

使用Saxon 9,它会转换输入

<Records>
  <Record>
    <Id>1</Id>
    <Name>table_id</Name>
    <Attribute></Attribute>
    <Value>1</Value>
  </Record>
  <Record>
    <Id>1</Id>
    <Name>score</Name>
    <Attribute></Attribute>
    <Value>2.1</Value>
  </Record>
  <Record>
    <Id>1</Id>
    <Name>custom4</Name>
    <Attribute>name</Attribute>
    <Value>Custom411</Value>
  </Record>
  <Record>
    <Id>1</Id>
    <Name>custom4</Name>
    <Attribute>name</Attribute>
    <Value>Custom412</Value>
  </Record>
  <Record>
    <Id>2</Id>
    <Name>table_id</Name>
    <Attribute></Attribute>
    <Value>2</Value>
  </Record>
  <Record>
    <Id>2</Id>
    <Name>title</Name>
    <Attribute></Attribute>
    <Value>Title 2</Value>
  </Record>
</Records>

进入以下结果:

<RECORDS>
   <RECORD>
      <ITEM name="table_id" value="1"/>
      <ITEM name="score" value="2.1"/>
      <LIST name="custom4">
         <LIST_ITEM value="Custom411"/>
         <LIST_ITEM value="Custom412"/>
      </LIST>
   </RECORD>
   <RECORD>
      <ITEM name="table_id" value="2"/>
      <ITEM name="title" value="Title 2"/>
   </RECORD>
</RECORDS>