【问题标题】:XSLT - how to conditionally group elements using template matchXSLT - 如何使用模板匹配有条件地对元素进行分组
【发布时间】:2020-05-11 21:02:29
【问题描述】:

这是我当前 XML 的一个示例:

<A>1</A>
<B>abc</B>
<A>1</A>
<B>def</B>
<A>2</A>
<B>ghi</B>
<B>jkl</B>
<A>3</A>
<B>012</B>

所以我使用 XSLT 来消除重复值,这很好并且有效:

<xsl:template match="A[preceding-sibling::A = current()]"/>

但是,我的下一步是使用 XSLT 包装具有相同 A 值的每组元素,例如:

<GROUP>
  <A>1</A>
  <B>abc</B>
  <B>def</B>
</GROUP>
<GROUP>
  <A>2</A>
  <B>ghi</B>
  <B>jkl</B>
</GROUP>
<GROUP>
  <A>3</A>
  <B>012</B>
</GROUP>

我被困在这个问题上,绝对可以在这方面使用一些帮助。我正在尝试使用follow-sibling 和previous-sibling,但似乎被卡住了。任何提示和/或帮助指出我正确的方向将不胜感激。

编辑:我的处理器支持 XSLT 1.0、2.0 或 3.0。

【问题讨论】:

  • XSLT 1.0 与 XSLT 2.0 或更高版本的分组非常不同。您的处理器支持哪个版本?
  • 嗯,它支持 XSLT 2.0 和 3.0(当然除了 1.0)。

标签: xml xslt


【解决方案1】:

使用你可以使用的键

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:key name="a" match="A" use="."/>
  <xsl:key name="b" match="B" use="preceding-sibling::A[1]"/>

  <xsl:template match="A[not(key('a', .)[1] is .)] | B"/>

  <xsl:template match="A[key('a', .)[1] is .]">
      <GROUP>
          <xsl:copy-of select="., key('b', .)"/>
      </GROUP>
  </xsl:template>

</xsl:stylesheet>

在 XSLT 2 或 3 (https://xsltfiddle.liberty-development.net/6pS26mY/) 和

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

  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="a" match="A" use="."/>
  <xsl:key name="b" match="B" use="preceding-sibling::A[1]"/>

  <xsl:template match="A[not(generate-id(key('a', .)[1]) = generate-id())] | B"/>

  <xsl:template match="A[generate-id(key('a', .)[1]) = generate-id()]">
      <GROUP>
          <xsl:copy-of select=". | key('b', .)"/>
      </GROUP>
  </xsl:template>

</xsl:stylesheet>

在 XSLT 1 中 (https://xsltfiddle.liberty-development.net/6pS26mY/1)

所以这基本上意味着在您的主题中使用模板匹配,通常在 XSLT 2/3 for-each-group group-starting-with / group-by 中是分组工具。

【讨论】:

    【解决方案2】:

    首先,您查找 A 的不同值的方法可能有效,但这不是一个好方法 - 在这里查看原因:http://www.jenitennison.com/xslt/grouping/muenchian.html

    现在,假设您仅限于 XSLT 1.0,以下是如何将 Muenchian 方法扩展到您的案例:

    XML

    <root>
        <A>1</A>
        <B>abc</B>
        <A>1</A>
        <B>def</B>
        <A>2</A>
        <B>ghi</B>
        <B>jkl</B>
        <A>3</A>
        <B>012</B>
    </root>
    

    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="a" match="A" use="." />
    <xsl:key name="b" match="B" use="preceding-sibling::A[1]" />
    
    <xsl:template match="/root">
        <output>
            <!-- a group for each distinct value of A -->
            <xsl:for-each select="A[count(. | key('a', .)[1]) = 1]">
                <GROUP>
                    <xsl:copy-of select="."/>
                    <!-- get the B's associated with this value -->
                    <xsl:copy-of select="key('b', .)"/>
                </GROUP>    
            </xsl:for-each>
        </output>
    </xsl:template>
    
    </xsl:stylesheet>
    

    结果

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
      <GROUP>
        <A>1</A>
        <B>abc</B>
        <B>def</B>
      </GROUP>
      <GROUP>
        <A>2</A>
        <B>ghi</B>
        <B>jkl</B>
      </GROUP>
      <GROUP>
        <A>3</A>
        <B>012</B>
      </GROUP>
    </output>
    

    在 XSLT 2.0 中,这可以简化为:

    XSLT 2.0

    <xsl:stylesheet version="2.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="b" match="B" use="preceding-sibling::A[1]" />
    
    <xsl:template match="/root">
        <output>
            <xsl:for-each-group select="A"  group-by=".">
                <GROUP>
                    <xsl:copy-of select="."/>
                    <xsl:copy-of select="key('b', .)"/>
                </GROUP>    
            </xsl:for-each-group>
        </output>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 2011-06-29
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多