Tim Dodgson
Tim Dodgson

Reputation: 1

Select node to iterate via XSL

I am in the process of developing a Free shopping cart gateway, which store's each item as XML

So given the following XML structure

<basket>
    <item id="1">
        <item-title>value</item-title>
        <item-description>value</item-description>
        <item-quanity>value</item-quanity>
        <item-price>value</item-price>
        <item-on>value</item-on>
        <item-os>value</item-os>
        <item-on>value</item-on>
        <item-os>value</item-os>
        <item-on>value</item-on>
        <item-os>value</item-os>
    </item>
    <item id="2">
        <item-title>value</item-title>
        <item-description>value</item-description>
        <item-quanity>value</item-quanity>
        <item-price>value</item-price>
        <item-on>value</item-on>
        <item-os>value</item-os>
        <item-on>value</item-on>
        <item-os>value</item-os>
    </item>
</basket>

Is it possible via XSL to select only the option nodes per item

So in short i never know how many options per item will be submitted, and i would like to display the option in the basket

at the moment i am using this XML stucture

<item id="1">
    <options>
        <option index="0">
            <on>Color</on>
            <os>Blue</os>
        </option>
        <option index="1">
            <on>Size</on>
            <os>5</os>
        </option>
    </options>
    <quantity>1</quantity>
    <item-name>Skate Board Trainers</item-name>
    <item-description>0011005</item-description>
    <unit-price>1.00</unit-price>
    <item-img>images/skate.gif</item-img>
    <item-url>http://cgdomestics2-co-uk.server9.controldns.co.uk/dev3/</item-url>
</item>
<item id="2">
    <options>
        <option index="0">
            <on>Color</on>
            <os>Blue</os>
        </option>
    </options>
    <quantity>1</quantity>
    <item-name>Tattoo Bottle Cap Belt - Recycled</item-name>
    <item-description>0011w346</item-description>
    <unit-price>1.00</unit-price>
    <item-img>images/belt.gif</item-img>
    <item-url>http://cgdomestics2-co-uk.server9.controldns.co.uk/dev3/</item-url>
</item>

So in the XSL i can simly select thr the options node and iterate round them, but to produce this stucture make the form to XML conversion really complecated and was hoping it would be simpler from XSL

Upvotes: 0

Views: 361

Answers (2)

user357812
user357812

Reputation:

With a more classic XSLT approach, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="item-os"/>
    <xsl:template match="item-on">
        <option index="{count(preceding-sibling::item-on)+1}">
            <xsl:apply-templates
                 select=".|following-sibling::*[1]/self::item-os"
                 mode="output"/>
        </option>
    </xsl:template>
    <xsl:template match="*" mode="output">
        <xsl:element name="{substring-after(name(),'item-')}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Output:

<basket>
    <item id="1">
        <item-title>value</item-title>
        <item-description>value</item-description>
        <item-quanity>value</item-quanity>
        <item-price>value</item-price>
        <option index="1">
            <on>value</on>
            <os>value</os>
        </option>
        <option index="2">
            <on>value</on>
            <os>value</os>
        </option>
        <option index="3">
            <on>value</on>
            <os>value</os>
        </option>
    </item>
    <item id="2">
        <item-title>value</item-title>
        <item-description>value</item-description>
        <item-quanity>value</item-quanity>
        <item-price>value</item-price>
        <option index="1">
            <on>value</on>
            <os>value</os>
        </option>
        <option index="2">
            <on>value</on>
            <os>value</os>
        </option>
    </item>
</basket>

Note: Identity rule copy input as is. "item-on" rule output option element having an @index with AVT and process self and next sibling if it's a item-so element in "output" mode. Empty "item-so" rule. "any element in output mode" rule, generate element with dynamic name and apply templates.

Upvotes: 1

Joe Daley
Joe Daley

Reputation: 46456

You can use following-sibling.

Input XML:

<?xml version="1.0" encoding="utf-8" ?>
<basket>
  <item id="1">
    <item-title>Item 1</item-title>
    <item-on>Color</item-on>
    <item-os>Blue</item-os>
    <item-on>Size</item-on>
    <item-os>5</item-os>
  </item>
  <item id="2">
    <item-title>Item 2</item-title>
    <item-on>Color</item-on>
    <item-os>Red</item-os>
  </item>
</basket>

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <basket>
      <xsl:for-each select="basket/item">
        <item id="{@id}">
          <item-title><xsl:value-of select="item-title"/></item-title>
          <options>
            <xsl:for-each select="item-on">
              <option>
                <on><xsl:value-of select="."/></on>
                <os><xsl:value-of select="following-sibling::item-os"/></os>
              </option>
            </xsl:for-each>
          </options>
        </item>
      </xsl:for-each>
    </basket>
  </xsl:template>
</xsl:stylesheet>

Output:

<?xml version="1.0" encoding="utf-8"?>
<basket>
  <item id="1">
    <item-title>Item 1</item-title>
    <options>
      <option>
        <on>Color</on>
        <os>Blue</os>
      </option>
      <option>
        <on>Size</on>
        <os>5</os>
      </option>
    </options>
  </item>
  <item id="2">
    <item-title>Item 2</item-title>
    <options>
      <option>
        <on>Color</on>
        <os>Red</os>
      </option>
    </options>
  </item>
</basket>

Upvotes: 0

Related Questions