Grouping with no relation

喜欢而已 提交于 2019-12-11 11:26:32

问题


Xml:

<items>
    <transaction>
        <header>
            <col1>H</col1>
            <col2>XXXX</col2>
            <col3>YYY12345</col3>
            <col4/>
            <col5>YYY12345A1234</col5>
        </header>
    </transaction>
    <item>
        <col1>D</col1>
        <col2>1</col2>
        <col3>5358478</col3>
        <col4>-1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>2</col2>
        <col3>9477498</col3>
        <col4>1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>2</col2>
        <col3>9477498</col3>
        <col4>1.0000</col4>
        <col5>CA</col5>
    </item>
    <transaction>
        <header>
            <col1>H</col1>
            <col2>XXXX</col2>
            <col3>YYY12345</col3>
            <col4/>
            <col5>YYY12345A1236</col5>
        </header>
    </transaction>
    <item>
        <col1>D</col1>
        <col2>1</col2>
        <col3>1676600</col3>
        <col4>1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>2</col2>
        <col3>5602891</col3>
        <col4>1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>3</col2>
        <col3>7990401</col3>
        <col4>2.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>4</col2>
        <col3>6985683</col3>
        <col4>1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>5</col2>
        <col3>9477498</col3>
        <col4>-1.0000</col4>
        <col5>CA</col5>
    </item>
    <item>
        <col1>D</col1>
        <col2>5</col2>
        <col3>9477498</col3>
        <col4>-1.0000</col4>
        <col5>CA</col5>
    </item>
</items>

Desired output:

<items>
    <transaction>
        <header>
            <col1>H</col1>
            <col2>XXXX</col2>
            <col3>YYY12345</col3>
            <col4/>
            <col5>YYY12345A1234</col5>
        </header>
        <item>
            <col1>D</col1>
            <col2>1</col2>
            <col3>5358478</col3>
            <col4>-1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>2</col2>
            <col3>9477498</col3>
            <col4>1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>2</col2>
            <col3>9477498</col3>
            <col4>1.0000</col4>
            <col5>CA</col5>
        </item>
    </transaction>
    <transaction>
        <header>
            <col1>H</col1>
            <col2>XXXX</col2>
            <col3>YYY12345</col3>
            <col4/>
            <col5>YYY12345A1236</col5>
        </header>
        <item>
            <col1>D</col1>
            <col2>1</col2>
            <col3>1676600</col3>
            <col4>1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>2</col2>
            <col3>5602891</col3>
            <col4>1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>3</col2>
            <col3>7990401</col3>
            <col4>2.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>4</col2>
            <col3>6985683</col3>
            <col4>1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>5</col2>
            <col3>9477498</col3>
            <col4>-1.0000</col4>
            <col5>CA</col5>
        </item>
        <item>
            <col1>D</col1>
            <col2>5</col2>
            <col3>9477498</col3>
            <col4>-1.0000</col4>
            <col5>CA</col5>
        </item>
    </transaction>
</items>

I am trying to do it in xslt 1.0. I'm having hard time figuring out how to move those item elements inside the transaction block.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

回答1:


After spending a few minutes reformatting your sample input and output and using diff, I think what you are trying to do is just move all the siblings of a transaction element into the transaction element as new children. True?

Adding the following templates to your stylesheet produces a stylesheet which produces the desired output.

First, the template for items calls apply-templates only for its transaction children (since they are the only ones whose output should appear as children of the output items element):

<xsl:template match="items">
  <items>
    <xsl:apply-templates select="transaction"/>
  </items>
</xsl:template>

The template for transaction calls apply-templates first for its children, in the default mode. (This handles the header element.) Then it calls apply-templates on its immediate right sibling (which will become the first item child of the transaction element in the output), in a special mode (here called items).

<xsl:template match="transaction">
  <transaction>
    <xsl:apply-templates/>
    <xsl:apply-templates 
        mode="items" 
        select="following-sibling::*[1]"/>
  </transaction>
</xsl:template>

The items mode is specialized for collecting the items of a given transaction. It exploits the fact that the items are all siblings, all are copied verbatim to the output, and the sequence of items ends when the next transaction sibling is found.

So the template for item in the items mode does two things: first it copies itself, then it applies templates, still in items mode, to its immediate right sibling. If that's another item, we will end up evaluating this template again. And again. And so on. (If you have extremely numerous items and a weak XSLT optimizer, requirements for stack memory may climb.)

<xsl:template match="item" mode="items">
  <xsl:copy-of select="."/>
  <xsl:apply-templates 
      mode="items" 
      select="following-sibling::*[1]"/>
</xsl:template>

Eventually, the immediate right sibling of an item element is going to be a transaction element. At that point, we want the recursion to stop, so the items-mode template for transaction does nothing. (It doesn't need to handle the transaction, because the default-mode template for transaction will do so.)

<xsl:template match="transaction" mode="items"/>

The right-sibling-recursion pattern is worth learning; it makes grouping tasks like this one simple.



来源:https://stackoverflow.com/questions/12903210/grouping-with-no-relation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!