使用XSLT 1.0在具有相同名称的密钥存在于不同级别时进行分组

时间:2017-06-30 11:28:33

标签: xslt xslt-1.0

我有以下输入xml:

    <?xml version="1.0" encoding="UTF-8"?>
<root>
   <results>
      <case>
         <KEY>c1</KEY>
         <issue>
            <KEY>i1</KEY>
            <id>Apple</id>
         </issue>
         <issue>
            <KEY>i1</KEY>
            <id>Orange</id>
         </issue>
         <issue>
            <KEY>i2</KEY>
            <id>Mango</id>
         </issue>
      </case>
      <case>
         <KEY>c1</KEY>
         <issue>
            <KEY>i5</KEY>
            <id>Apricot</id>
         </issue>
         <issue>
            <KEY>i5</KEY>
            <id>Blueberry</id>
         </issue>
         <issue>
            <KEY>i6</KEY>
            <id>blackberry</id>
         </issue>
      </case>
      <case>
         <KEY>c2</KEY>
         <issue>
            <KEY>i3</KEY>
            <id>Banana</id>
         </issue>
         <issue>
            <KEY>i3</KEY>
            <id>Cherry</id>
         </issue>
         <issue>
            <KEY>i4</KEY>
            <id>Grapes</id>
         </issue>
      </case>
   </results>
</root>

现在我想先<KEY> <case>分组,然后<KEY> <issue>分组。我们的想法是通过问题密钥和案例密钥对所有<issue>进行分组。最后,我想移动<id><sourceInstance>节点下问题键相同的所有<issue>

我的输出xml应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <results>
      <case>
         <KEY>c1</KEY>
         <issue>
            <KEY>i1</KEY>
            <sources>
               <sourceInstance>
                  <id>Apple</id>
               </sourceInstance>
               <sourceInstance>
                  <id>Orange</id>
               </sourceInstance>
            </sources>
         </issue>
         <issue>
            <KEY>i2</KEY>
            <sources>
               <sourceInstance>
                  <id>Mango</id>
               </sourceInstance>
            </sources>
         </issue>
         <issue>
            <KEY>i5</KEY>
            <sources>
               <sourceInstance>
                  <id>Apricot</id>
               </sourceInstance>
               <sourceInstance>
                  <id>Blueberry</id>
               </sourceInstance>
            </sources>
         </issue>
         <issue>
            <KEY>i6</KEY>
            <sources>
               <sourceInstance>
                  <id>Apple</id>
               </sourceInstance>
               <sourceInstance>
                  <id>Orange</id>
               </sourceInstance>
            </sources>
         </issue>
      </case>
      <case>
         <KEY>c2</KEY>
         <issue>
            <KEY>i3</KEY>
            <sources>
               <sourceInstance>
                  <id>Banana</id>
               </sourceInstance>
               <sourceInstance>
                  <id>Cherry</id>
               </sourceInstance>
            </sources>
         </issue>
         <issue>
            <KEY>i4</KEY>
            <sources>
               <sourceInstance>
                  <id>Grapes</id>
               </sourceInstance>
            </sources>
         </issue>
      </case>
   </results>
</root>

我尝试使用以下XSLT,但无法获得所需的xml输出。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes" />
   <xsl:key name="case" match="case" use="string(KEY)" />
   <xsl:key name="issue" match="case" use="concat(KEY, '|', KEY)" />
   <xsl:template match="results">
      <xsl:copy>
         <xsl:apply-templates select="case[generate-id() = generate-id(key('case', string(KEY))[1])]" mode="case" />
      </xsl:copy>
   </xsl:template>
   <xsl:template match="case" mode="case">
      <xsl:choose>
         <xsl:when test="KEY">
            <case>
               <xsl:copy-of select="KEY" />
               <xsl:apply-templates select="key('case', KEY)[generate-id() = generate-id(key('issue', concat(KEY, '|', KEY))[1])]" mode="issue" />
            </case>
         </xsl:when>
      </xsl:choose>
   </xsl:template>
   <xsl:template match="case " mode="issue">
      <xsl:choose>
         <xsl:when test="KEY">
            <issue>
               <xsl:copy-of select="KEY" />
               <sources>
                  <xsl:apply-templates select="key('issue', id)" />
               </sources>
            </issue>
         </xsl:when>
      </xsl:choose>
   </xsl:template>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
   </xsl:template>
   <xsl:template match="case">
      <sourceInstance>
         <id>
            <xsl:value-of select="id" />
         </id>
      </sourceInstance>
   </xsl:template>
</xsl:stylesheet>

我似乎无法使用<KEY> <case><issue>作为具有相同名称的节点(即<KEY>来构建正确的密钥组合框架)存在于两个地方。

有人能告诉我在XSLT中缺少什么吗?

1 个答案:

答案 0 :(得分:2)

主要问题是issue

键的定义
<xsl:key name="issue" match="case" use="concat(KEY, '|', KEY)" />

您需要在此处匹配issue元素,并使用issue和父case元素的KEY的串联

<xsl:key name="issue" match="issue" use="concat(KEY, '|', ../KEY)" />

然后,要获取给定issue KEY的分组case元素,您可以这样做...

<xsl:apply-templates select="key('case', KEY)/issue[generate-id() = generate-id(key('issue', concat(KEY, '|', ../KEY))[1])]" mode="issue" />

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes" />
   <xsl:key name="case" match="case" use="string(KEY)" />
   <xsl:key name="issue" match="issue" use="concat(KEY, '|', ../KEY)" />

   <xsl:template match="results">
      <xsl:copy>
         <xsl:apply-templates select="case[generate-id() = generate-id(key('case', string(KEY))[1])]" mode="case" />
      </xsl:copy>
   </xsl:template>

   <xsl:template match="case" mode="case">
      <xsl:choose>
         <xsl:when test="KEY">
            <case>
               <xsl:copy-of select="KEY" />
               <xsl:apply-templates select="key('case', KEY)/issue[generate-id() = generate-id(key('issue', concat(KEY, '|', ../KEY))[1])]" mode="issue" />
            </case>
         </xsl:when>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="issue" mode="issue">
      <xsl:choose>
         <xsl:when test="KEY">
            <issue>
               <xsl:copy-of select="KEY" />
               <sources>
                  <xsl:apply-templates select="key('issue', concat(KEY, '|', ../KEY))" />
               </sources>
            </issue>
         </xsl:when>
      </xsl:choose>
   </xsl:template>

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

   <xsl:template match="issue">
      <sourceInstance>
         <id>
            <xsl:value-of select="id" />
         </id>
      </sourceInstance>
   </xsl:template>
</xsl:stylesheet>