0

I have the following list of items.

<items>
    <item type="Type1">Item1</item>
    <item type="Type2">Item2<item>
    <item type="Type2">Item3<item>
    <item type="Type3">Item4<item>
    <item type="Type3">Item5<item>
    <item type="Type1">Item6<item>
    <item type="Type3">Item7<item>
    <item type="Type1">Item8<item>
    <item type="Type2">Item9<item>
    <item type="Type1">Item10<item>
<items>

I'm having trouble figuring out the XSLT required so that the above are displayed in groups of Type1(x1), Type2(x2), Type3(x4), where the counts are the number in parenthesis or less. In other words, the goal is to create a repeating pattern: the next item of Type1 if any of those remain, then the next two items of Type2 or fewer if less than two remain, then the next four items of Type3 or fewer if less than four remain.

So the desired output would look something like the below:

<div class="Items">
    <div class="Type1">Item1</div>
    <div class="Type2">Item2</div>
    <div class="Type2">Item3</div>
    <div class="Type3">Item4</div>
    <div class="Type3">Item5</div>
    <div class="Type3">Item7</div>
    <div class="Type1">Item6</div>
    <div class="Type2">Item9</div>
    <div class="Type1">Item8</div>
    <div class="Type1">Item10</div>
</div>

From the above output, you can see that the ordering has changed. i.e. there is <=1 Type 1, followed by <=2 Type2, followed by <=4 Type3, and this pattern repeats itself. I suppose the items will need to be grouped into the pattern described and repeat itself until the full list if items are exhausted. I hope I make sense.

Can anyone provide the required XSLT or some pointers please?

Thanks, John.

4

1 回答 1

0

Please give this a whirl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="kType2Group" match="item[@type = 'Type2']"
           use="floor(count(preceding-sibling::item[@type = 'Type2']) div 2) + 1"/>
  <xsl:key name="kType3Group" match="item[@type = 'Type3']"
           use="floor(count(preceding-sibling::item[@type = 'Type3']) div 4) + 1"/>

  <xsl:template match="@* | node()" name="Copy">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="item[@type = 'Type1']" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item[@type = 'Type1']">
    <xsl:call-template name="Copy" />
    <xsl:apply-templates select="key('kType2Group', position())" />
    <xsl:apply-templates select="key('kType3Group', position())" />
  </xsl:template>
</xsl:stylesheet>

When run on your input XML, the result is:

<items>
  <item type="Type1">Item1</item>
  <item type="Type2">Item2</item>
  <item type="Type2">Item3</item>
  <item type="Type3">Item4</item>
  <item type="Type3">Item5</item>
  <item type="Type3">Item7</item>
  <item type="Type1">Item6</item>
  <item type="Type2">Item9</item>
  <item type="Type1">Item8</item>
  <item type="Type1">Item10</item>
</items>

The keys in this case are used to separate the Type2 and Type3 items into groups, so that they can be retrieved by their group number (1, 2, 3, etc.) the logic for determining the group numbers is to count the number of preceding items of the same type, divide that number by the number of items in each group, round down, and add one. So for example, this calculation carried out for the first four Type2s would be:

floor(0 div 2) + 1 = floor(0) + 1 = 0 + 1 = 1
floor(1 div 2) + 1 = floor(0.5) + 1 = 0 + 1 = 1
floor(2 div 2) + 1 = floor(1) + 1 = 1 + 1 = 2
floor(3 div 2) + 1 = floor(1.5) + 1 = 1 + 1 = 2

and so on.

The general logic of the XSLT is:

  • Match the root element, copy it, and apply templates to all Type1 items.
  • The template for Type1 items:
    • Copies the item itself.
    • Uses the key to apply templates to the Type2 items in its group (position() will be 1 for the first Type1 item, 2 for the second, and so on.
    • Uses the key to apply templates to the Type3 items in its group
  • The first template, the identity template, does the job of copying anything that doesn't have any other template to match it.
于 2013-05-16T06:11:00.250 回答