问题
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