我想更好地理解使用Muenchian分组的XSLT 1.0嵌套分组

时间:2014-09-18 15:15:13

标签: xml xslt

我有XML数据,并希望通过INSPTR和ELVINSP_DT对其进行分组。帖子末尾的问题。

这是我的XML:

<AS400_ELVPINS00Collection>
  <ObjList>
    <AS400_ELVPINS00>
      <ID>123456</ID>
      <ELVINSP_DT>2014-05-01</ELVINSP_DT>
      <DetailData>Out Sick</DetailData>
      <INSPTR>
        <ID>555123</ID>
        <INSPTR_NAME>Doe, John P</INSPTR_NAME>
        <MoreDetailData>Northeast Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
    <AS400_ELVPINS00>
      <ID>123459</ID>
      <ELVINSP_DT>2014-05-02</ELVINSP_DT>
      <DetailData>Nobody showed up</DetailData>
      <INSPTR>
        <ID>555123</ID>
        <INSPTR_NAME>Doe, John P</INSPTR_NAME>
        <MoreDetailData>Northeast Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
    <AS400_ELVPINS00>
      <ID>123463</ID>
      <ELVINSP_DT>2014-05-01</ELVINSP_DT>
      <DetailData>Job Location was clear</DetailData>
      <INSPTR>
        <ID>555124</ID>
        <INSPTR_NAME>Smith, John T</INSPTR_NAME>
        <MoreDetailData>South Central Region</MoreDetailData>
      </INSPTR>
    </AS400_ELVPINS00>
  </ObjList>
</AS400_ELVPINS00Collection>

我希望列出的数据如下:

Doe, John P  
 2014-05-01 - Out Sick  
 2014-05-02 - Nobody showed up  
Smith, John T  
 2014-05-01 - Job Location was clear  

以下是我正在为XSLT尝试的内容:

  <xsl:key name="keyInsptr" match="ObjList/AS400_ELVPINS00" use="INSPTR" />
  <xsl:key name="keyDate" match="ObjList/AS400_ELVPINS00" use="ELVINSP_DT" />

    <fo:flow flow-name="xsl-region-body">
      <xsl:for-each select="ObjList/AS400_ELVPINS00[generate-id(.)=generate-id(key('keyInsptr',INSPTR)[1])]">
        <xsl:sort select="INSPTR/INSPTR_NAME"/>

        <!-- This part works --> 
        <fo:block>
          <xsl:value-of select="INSPTR/INSPTR_NAME" />
        </fo:block>

        <!-- This part DOES NOT work -->
        <xsl:variable name="vrInsptID">
          <xsl:value-of select="INSPTR/INSPTR_NAME"/>
        </xsl:variable>
        <xsl:variable name="lstInsp" select="ObjList/AS400_ELVPINS00[INSPTR/INSPTR_NAME=vrInsptrID]" />
        <xsl:for-each select="lstInsp[generate-id(.)=generate-id(key('keyDate',ELVINSP_DT)[1])]">
          <fo:block>
            <xsl:text> - </xsl:text>
            <xsl:call-template name="dateFormat">
              <xsl:with-param name="value" select="lstInsp/ELVINSP_DT" />
            </xsl:call-template>
          </fo:block>
        </xsl:for-each>


      </xsl:for-each>
    </fo:flow>

我理解generate-id在运行时为元素创建一个唯一的'id',所以我假设generate-id(。)将为匹配中使用的每个ObjList / AS400_ELVPINS00元素生成一个id,对吗?

什么是generate-id(key('keyInsptr',INSPTR)[1])在做什么?这会产生什么样的结果?我想把它想象一下。

当我在keyInsptr上执行'for-each'时,我在内部使用什么Node-set?

如何让内部'for-each'正确地循环显示日期?

我不只是想让这个工作,但也要了解它应该如何工作。谢谢。

1 个答案:

答案 0 :(得分:1)

如果您是Muenchian分组的新手,并且不了解这个概念,那么我不认为使用嵌套分组和两个键启动项目是一个好主意。至于你理解谓词generate-id(.)=generate-id(key('keyInsptr',INSPTR)[1])的问题,它只是确保for-each根据键值处理每个组中的第一个项目,因为表达式key('keyInsptr',INSPTR)找到了相同键的所有项目值,位置谓词key('keyInsptr',INSPTR)[1]采用这些项中的第一项,而generate-id检查只是比较两个节点标识的XSLT / XPath 1.0方式(使用XPath 2.0,你可以写[. is key('keyInsptr',INSPTR)[1]]虽然你会使用for-each-group代替。因此

  <xsl:for-each select="ObjList/AS400_ELVPINS00[generate-id(.)=generate-id(key('keyInsptr', INSPTR)[1])]">

处理具有相同键值的每个组的第一个AS400_ELVPINS00(按文档顺序)。

现在为了扩展分组,通常将键值与不在预期键值中的分隔符连接起来,所以使用

  <xsl:key name="keyDate" match="ObjList/AS400_ELVPINS00" use="concat(INSPTR, '|', ELVINSP_DT)" />

    <xsl:for-each select="key('keyInsptr', INSPTR)[generate-id(.)=generate-id(key('keyDate', concat(INSPTR, '|', ELVINSP_DT))[1])]">
      <fo:block>
        <xsl:text> - </xsl:text>
        <xsl:call-template name="dateFormat">
          <xsl:with-param name="value" select="ELVINSP_DT" />
        </xsl:call-template>
      </fo:block>
    </xsl:for-each>

您将实施第二级分组。