XSLT对子段和父段进行排序和分组

时间:2019-02-05 08:32:56

标签: xslt

我有一个具有以下结构的xml:

<Order>
    <Top>
    </Top>
    <Body>
        <Line>
            <Ref>
                <PO>1</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>1</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>3</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>3</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>2</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>2</PO>
            </Ref>
        </Line>
    </Body>
</Order>

我需要按Ref / PO对Line进行排序和分组,然后为每组Line复制父节点,如下例所示。

<Order>
    <Top>
    </Top>
    <Body>
        <Line>
            <Ref>
                <PO>1</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>1</PO>
            </Ref>
        </Line>
    </Body>
</Order>
<Order>
    <Top>
    </Top>
    <Body>
        <Line>
            <Ref>
                <PO>2</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>2</PO>
            </Ref>
        </Line>
    </Body>
</Order>
<Order>
    <Top>
    </Top>
    <Body>
        <Line>
            <Ref>
                <PO>3</PO>
            </Ref>
        </Line>
        <Line>
            <Ref>
                <PO>3</PO>
            </Ref>
        </Line>
    </Body>
</Order>

这怎么办?我一直在寻找类似的问题,但没有找到完全匹配的内容,因此,如果我忽略了某些内容,请向我们道歉。感谢帮助。

2 个答案:

答案 0 :(得分:0)

假设至少XSLT 2在for-each-group所在的位置,则可以使用它进行分组和排序,然后只需重构结构

  <xsl:template match="Body">
      <xsl:for-each-group select="Line" group-by="Ref/PO">
          <xsl:sort select="xs:integer(current-grouping-key())"/>
          <xsl:copy select="../..">
              <xsl:copy-of select="* except Body"/>
              <Body>
                  <xsl:copy-of select="current-group()"/>
              </Body>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

https://xsltfiddle.liberty-development.net/bnnZVK/1包含完整的示例

<?xml version="1.0" encoding="UTF-8"?>
<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:mode on-no-match="shallow-skip"/>

  <xsl:output indent="yes"/>

  <xsl:template match="Body">
      <xsl:for-each-group select="Line" group-by="Ref/PO">
          <xsl:sort select="xs:integer(current-grouping-key())"/>
          <xsl:copy select="../..">
              <xsl:copy-of select="* except Body"/>
              <Body>
                  <xsl:copy-of select="current-group()"/>
              </Body>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

使用XSLT 3(但是对于带有xsl:copy select的XSLT 2,可以避免使用XSLT 3独有的xsl:element

  <xsl:template match="Body">
      <xsl:for-each-group select="Line" group-by="Ref/PO">
          <xsl:sort select="xs:integer(current-grouping-key())"/>
          <xsl:element name="{name(../..)}" namespace="{namespace-uri(../..)}">
              <xsl:copy-of select="../../(* except Body)"/>
              <Body>
                  <xsl:copy-of select="current-group()"/>
              </Body>
          </xsl:element>
      </xsl:for-each-group>
  </xsl:template>

http://xsltransform.net/pNEhB31

答案 1 :(得分:0)

<xsl:template match="Body">
<xsl:for-each-group select="Line" group-by="Ref/PO">
  <xsl:sort select="current-grouping-key()"/>
      <xsl:element name="order">
          <xsl:element name="top"></xsl:element>
          <Body>
              <xsl:copy-of select="current-group()"/>
          </Body>
      </xsl:element>
  </xsl:for-each-group>

    xslt 2.0