0

Yes, this is another XSLT grouping/duplicates questions, but I was unable to find any answers that I could successfully apply to my situation.

This is the original XML:

<data jsxid="jsxroot">
   <record jsxid="10" groupNum="1319" item="q123"  total="1"/>
   <record jsxid="20" groupNum="1319" item="w123"  total="1"/>
   <record jsxid="30" groupNum="1319" item=""  total="0"/>
   <record jsxid="40" groupNum="1322" item="z123" total="1"/>
   <record jsxid="50" groupNum="1322" item="x123" total="1"/>
   <record jsxid="60" groupNum="1322" item="c123" total="1"/>
   <record jsxid="70" groupNum="1322" item="" total="0"/>
   <record jsxid="80" groupNum="1323" item="x123" total="1"/>
   <record jsxid="90" groupNum="1323" item="c123" total="1"/>
   <record jsxid="100" groupNum="1323" item="z123" total="1"/>
   <record jsxid="110" groupNum="1323" item="" total="0"/>
</data>

First, I need it grouped by attribute "groupNum" and wrapped in a parent element jsxid that increments with each group, so that the output looks like this:

<data jsxid="jsxroot">
    <record jsxid="1">
        <record jsxid="10" groupNum="1319" item="q123"  total="1"/>
        <record jsxid="20" groupNum="1319" item="w123"  total="1"/>
        <record jsxid="30" groupNum="1319" item=""  total="0"/>
    </record>
    <record jsxid="2">  
        <record jsxid="40" groupNum="1322" item="z123" total="1"/>
        <record jsxid="50" groupNum="1322" item="x123" total="1"/>
        <record jsxid="60" groupNum="1322" item="c123" total="1"/>
        <record jsxid="70" groupNum="1322" item="" total="0"/>
    </record>
    <record jsxid="3">  
        <record jsxid="80" groupNum="1323" item="x123" total="1"/>
        <record jsxid="90" groupNum="1323" item="c123" total="1"/>
        <record jsxid="100" groupNum="1323" item="z123" total="1"/>
        <record jsxid="110" groupNum="1323" item="" total="0"/>
    </record>
</data>

I was able to accomplish that with this stylesheet:

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

    <xsl:output method="xml" indent="yes" />

    <xsl:key name="groupNum" match="data/*" use="@groupNum" />

    <xsl:template match="data">
    <data>
            <xsl:apply-templates select="*[generate-id(.)=generate-id(key('groupNum',@groupNum)[1])]"/>
    </data>
    </xsl:template>


    <xsl:template match="*">
        <record jsxid="{position()}" >
          <xsl:copy-of select="key('groupNum', @groupNum)" />
        </record>
    </xsl:template>

</xsl:stylesheet>

Now I need to remove any grouping that contains the exact same items as another grouping for records where total = "1". If you look at the groupings of jsxid = 2 and jsxid = 3 above, you'll see that they both contain the following item attributes, though not in the same order:

item="x123"
item="c123"
item="z123"

So I want to remove the entire jsxid = 3 grouping and have the final output look like this:

<data jsxid="jsxroot">
    <record jsxid="1">
        <record jsxid="1" groupNum="1319" item="q123"  total="1"/>
        <record jsxid="2" groupNum="1319" item="w123"  total="1"/>
        <record jsxid="3" groupNum="1319" item=""  total="0"/>
    </record>
    <record jsxid="2">  
        <record jsxid="4" groupNum="1322" item="z123" total="1"/>
        <record jsxid="5" groupNum="1322" item="x123" total="1"/>
        <record jsxid="6" groupNum="1322" item="c123" total="1"/>
        <record jsxid="7" groupNum="1322" item="" total="0"/>
    </record>
</data>

EDIT: Instead of removing the duplicate grouping, what if I wanted to add in a new attribute as a "grouping identifier." I'd call it something like "groupType" so the output for the above situation where the last two groupings are the same, they would have the same grouptype:

<data jsxid="jsxroot">
    <record jsxid="1">
        <record jsxid="10" groupNum="1319" item="q123"  groupType = "type1" total="1"/>
        <record jsxid="20" groupNum="1319" item="w123"  groupType = "type1" total="1"/>
        <record jsxid="30" groupNum="1319" item=""  groupType = "type1" total="0"/>
    </record>
    <record jsxid="2">  
        <record jsxid="40" groupNum="1322" item="z123" groupType = "type2" total="1"/>
        <record jsxid="50" groupNum="1322" item="x123" groupType = "type2" total="1"/>
        <record jsxid="60" groupNum="1322" item="c123" groupType = "type2" total="1"/>
        <record jsxid="70" groupNum="1322" item="" groupType = "type2" total="0"/>
    </record>
    <record jsxid="3">  
        <record jsxid="80" groupNum="1323" item="x123" groupType = "type2" total="1"/>
        <record jsxid="90" groupNum="1323" item="c123" groupType = "type2" total="1"/>
        <record jsxid="100" groupNum="1323" item="z123" groupType = "type2" total="1"/>
        <record jsxid="110" groupNum="1323" item="" groupType = "type2" total="0"/>
    </record>
</data>

Any help is greatly appreciated.

4

2 回答 2

0

这并不简单,所以请坐在你的座位上:

XSLT 1.0

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

<xsl:variable name="root" select="/" />

<xsl:key name="rec-by-group" match="record" use="@groupNum" />
<xsl:key name="group-by-items" match="group" use="@items" />

<xsl:template match="/">
    <!-- first pass -->
    <xsl:variable name="groups">
        <!-- for each unique groupNum ... -->
        <xsl:for-each select="data/record[count(. | key('rec-by-group', @groupNum)[1]) = 1]">
            <xsl:variable name="groupNum" select="@groupNum" />
            <!-- ... create a group ... -->
            <group groupNum="{$groupNum}">
                <!-- ... and concatenate all its items - in known order(!) - into a single attribute. -->
                <xsl:attribute name="items">
                    <!-- switch context back to document in order to use key -->
                    <xsl:for-each select="$root">
                        <xsl:for-each select="key('rec-by-group', $groupNum)[@total=1]">
                            <xsl:sort select="@item" data-type="text" order="ascending"/>
                            <xsl:value-of select="@item"/>
                            <xsl:text>|</xsl:text>
                        </xsl:for-each>
                    </xsl:for-each>
                </xsl:attribute>
            </group>
        </xsl:for-each>
    </xsl:variable>

    <!-- final pass -->
    <data jsxid="jsxroot">
        <!-- for each unique group (unique by its @items attribute) ... -->
        <xsl:for-each select="exsl:node-set($groups)/group[count(. | key('group-by-items', @items)[1]) = 1]">
            <!-- ... create a wrapper record ... -->
            <record jsxid="{position()}">
                <xsl:variable name="groupNum" select="@groupNum" />
                <!-- switch context back to document in order to use key -->
                <xsl:for-each select="$root">
                    <!-- ... and list the records in this group. -->
                    <xsl:for-each select="key('rec-by-group', $groupNum)">
                        <record>
                            <xsl:attribute name="jsxid">
                                <xsl:number/>
                            </xsl:attribute>
                            <xsl:copy-of select="@groupNum | @item | @total"/>
                        </record>
                    </xsl:for-each>
                </xsl:for-each>
            </record>
        </xsl:for-each>
    </data>
</xsl:template>

</xsl:stylesheet>

编辑:

回应您的编辑:

如果您可以groupType接受任意(尽管是唯一的)数字,则可以将“最终通过”部分更改为:

<!-- final pass -->
<data jsxid="jsxroot">
    <!-- for each group ... -->
    <xsl:for-each select="exsl:node-set($groups)/group">
        <!-- ... create a wrapper record ... -->
        <record jsxid="{position()}">
            <xsl:variable name="groupNum" select="@groupNum" />
            <xsl:variable name="groupType" select="key('group-by-items', @items)[1]/@groupNum" />
            <!-- switch context back to document in order to use key -->
            <xsl:for-each select="$root">
                <!-- ... and list the records in this group. -->
                <xsl:for-each select="key('rec-by-group', $groupNum)">
                    <record groupType="{$groupType}">
                        <xsl:attribute name="jsxid">
                            <xsl:number/>
                        </xsl:attribute>
                        <xsl:copy-of select="@groupNum | @item | @total"/>
                    </record>
                </xsl:for-each>
            </xsl:for-each>
        </record>
    </xsl:for-each>
</data>

使用您的输入示例,这将返回:

<?xml version="1.0" encoding="UTF-8"?>
<data jsxid="jsxroot">
   <record jsxid="1">
      <record groupType="1319" jsxid="1" groupNum="1319" item="q123" total="1"/>
      <record groupType="1319" jsxid="2" groupNum="1319" item="w123" total="1"/>
      <record groupType="1319" jsxid="3" groupNum="1319" item="" total="0"/>
   </record>
   <record jsxid="2">
      <record groupType="1322" jsxid="4" groupNum="1322" item="z123" total="1"/>
      <record groupType="1322" jsxid="5" groupNum="1322" item="x123" total="1"/>
      <record groupType="1322" jsxid="6" groupNum="1322" item="c123" total="1"/>
      <record groupType="1322" jsxid="7" groupNum="1322" item="" total="0"/>
   </record>
   <record jsxid="3">
      <record groupType="1322" jsxid="8" groupNum="1323" item="x123" total="1"/>
      <record groupType="1322" jsxid="9" groupNum="1323" item="c123" total="1"/>
      <record groupType="1322" jsxid="10" groupNum="1323" item="z123" total="1"/>
      <record groupType="1322" jsxid="11" groupNum="1323" item="" total="0"/>
   </record>
</data>

如您所见,它使用groupNum当前类型的第一组作为groupType值。或者,您也可以使用该组的自动生成的 id:

<xsl:variable name="groupType" select="generate-id(key('group-by-items', @items)[1])" />.
于 2014-10-08T00:48:30.850 回答
-1

要仅复制第一个实例,在生成每个项目时,将其包含在使用 count(preceding-sibling::*[]) = 0 的条件中。

<xsl:template match="record">
    <xsl:variable name="item" select="item"/>
    <record jsxid="{position()}" >
        <xsl:if test="count (preceding-sibling::*[item=$item])=0">
           <xsl:copy-of select="key('groupNum', @groupNum)" />
        </xsl:if>
    </record>
</xsl:template>
于 2014-10-07T23:56:33.743 回答