簡體   English   中英

使用XSLT 1.0通過分組來循環XML節點

[英]Loop XML nodes with grouping using XSLT 1.0

使用以下XML

<page>
  <chunk id="1001" sequence="1">
    <meta>Inline</meta>
    <body>Inline chunk 1</body>
  </chunk>
  <chunk id="1002" sequence="2">
    <meta>Tabs</meta>
    <body>Tab chunk 1</body>
  </chunk>
  <chunk id="1054" sequence="3">
    <meta>Tabs</meta>
    <body>Tab chunk 2</body>
  </chunk>
  <chunk id="1023" sequence="4">
    <meta>Inline</meta>
    <body>Inline chunk 2</body>
  </chunk>
  <chunk id="1013" sequence="5">
    <meta>Tabs</meta>
    <body>Tab chunk 3</body>
  </chunk>
  <chunk id="1072" sequence="6">
    <meta>Tabs</meta>
    <body>Tab chunk 4</body>
  </chunk>
</page>

我想應用XSL模板來輸出以下內容:

<main>
  <section class="Inline>
    <div>Inline chunk 1</div>
  </section>
  <section class="Tabs>
    <div>Tab chunk 1</div>
    <div>Tab chunk 2</div>
  </section>
  <section class="Inline>
    <div>Inline chunk 2</div>
  </section>
  <section class="Tabs>
    <div>Tab chunk 3</div>
    <div>Tab chunk 4</div>
  </section>
</main>

基本上,我想按./@sequence的順序輸出chunk ,但在可能時根據其./meta值對它們進行./meta “可能”是指僅將它們具有相同的./meta值並按順序排列在一起。

使用Muenchian方法,我可以將chunk./meta ,但只能得到以下結果:

<main>
  <section class="Inline>
    <div>Inline chunk 1</div>
    <div>Inline chunk 2</div>
  </section>
  <section class="Tabs>
    <div>Tab chunk 1</div>
    <div>Tab chunk 2</div>
    <div>Tab chunk 3</div>
    <div>Tab chunk 4</div>
  </section>
</main>

這是我使用的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="kBucketByLabel" match="/page/chunk" use="./meta" />

  <!-- Then we override/define a template to match "/SAM" and write our body HTML here. -->
  <xsl:template match="/page" mode="body">
    <main>
      <xsl:apply-templates select="chunk[generate-id() = generate-id( key('kBucketByLabel', ./meta)[1] )]" mode="bucket">
        <xsl:sort select="@sequence" data-type="number" />
      </xsl:apply-templates>
    </main>

  </xsl:template>

  <xsl:template match="chunk" mode="bucket">
    <xsl:variable name="bucket" select="./meta" />
    <section class="{$bucket}">
      <xsl:for-each select="key('kBucketByLabel', $bucket)">
        <div><xsl:value-of select="./body"/></div>
      </xsl:for-each>
    </section>
  </xsl:template>

</xsl:stylesheet>

一種實現方法是通過稱為“同級遞歸”的技術:

XSLT 1.0

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

<xsl:template match="/page">
    <main>
        <xsl:apply-templates select="chunk[not(meta = preceding-sibling::chunk[1]/meta)]"/>
    </main>
</xsl:template>

<xsl:template match="chunk">
    <section class="{meta}">
        <xsl:apply-templates select="." mode="collect"/>
    </section>
</xsl:template>

<xsl:template match="chunk" mode="collect">
    <div>
        <xsl:value-of select="body"/>
    </div>
    <xsl:apply-templates select="following-sibling::chunk[1][meta = current()/meta]" mode="collect"/>
</xsl:template> 

</xsl:stylesheet>

添加:

這可用於未分類的塊嗎? 在上面的示例數據中,我有意按@sequence對它們進行@sequence ,以便於可視化,但我的實際數據未排序。
...
我設法通過首先循環使用<xsl:for-each> chunk對它們進行排序,按@sequence對其進行@sequence ,並將其副本存儲到RTF。 我不得不使用擴展將RTF轉換為節點集並應用您的技術。 它有效,但我希望盡可能不要這樣做。

實際上,這正是我要做的:首先對數據進行排序,將其轉換為節點集,然后在第二遍中應用上述方法。

如果您不想這樣做,則可以使用來引用序列中的上一個/下一個塊,前提是該序列是連續的:

XSLT 1.0

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

<xsl:key name="chunk" match="chunk" use="@sequence" />

<xsl:template match="/page">
    <main>
        <xsl:apply-templates select="chunk[not(meta = key('chunk', @sequence - 1)/meta)]">
            <xsl:sort select="@sequence" data-type="number" order="ascending"/>
        </xsl:apply-templates>
    </main>
</xsl:template>

<xsl:template match="chunk">
    <section class="{meta}">
        <xsl:apply-templates select="." mode="collect"/>
    </section>
</xsl:template>

<xsl:template match="chunk" mode="collect">
    <div>
        <xsl:value-of select="body"/>
    </div>
    <xsl:apply-templates select="key('chunk', @sequence + 1)[meta = current()/meta]" mode="collect"/>
</xsl:template> 

</xsl:stylesheet>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM