madeinevo
madeinevo

Reputation: 33

compare xml nodes and select via xslt:for-each

I would like to select the images in the Xml document by comparing them with the colors. position() not use, because image links mixed order. if I know how many times the for-each cycle is in the loop, but I can not find it

Source XML Document:

<?xml version="1.0" encoding="UTF-8" ?>
<products>
    <product>
        <ws_code>61W9232-MZ</ws_code>
        <images>
            <img_item type_name="BLACK">black-1.jpg</img_item>
            <img_item type_name="BLACK">black-2.jpg</img_item>
            <img_item type_name="BLUE">blue-1.jpg</img_item>
            <img_item type_name="BLACK">black-3.jpg</img_item>
            <img_item type_name="BLACK">black-4.jpg</img_item>
            <img_item type_name="NAVY">navy-1.jpg</img_item>
            <img_item type_name="NAVY">navy-2.jpg</img_item>
            <img_item type_name="RED">red-1.jpg</img_item>
            <img_item type_name="NAVY">navy-3.jpg</img_item>
            <img_item type_name="NAVY">navy-4.jpg</img_item>
            <img_item type_name="RED">red-2.jpg</img_item>
            <img_item type_name="BLUE">blue-2.jpg</img_item>
            <img_item type_name="">empty</img_item>
        </images>
        <subproducts>
            <subproduct>
                <code>6675</code>
                <color><![CDATA[BLACK]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6676</code>
                <color><![CDATA[BLACK]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6677</code>
                <color><![CDATA[NAVY]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6678</code>
                <color><![CDATA[NAVY]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6679</code>
                <color><![CDATA[BLUE]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6680</code>
                <color><![CDATA[BLUE]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6681</code>
                <color><![CDATA[RED]]></color>
                <stock>3</stock>
            </subproduct>
            <subproduct>
                <code>6682</code>
                <color><![CDATA[RED]]></color>
                <stock>3</stock>
            </subproduct>   
        </subproducts>
    </product>
</products>

XSLT Document:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="maxEventNum" select="0"/>

    <xsl:template match="/">
        <products>
            <xsl:apply-templates/>
        </products>
    </xsl:template>

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

    <xsl:template match="/products/product/subproducts/subproduct">
        <xsl:if test="stock &gt; $maxEventNum">

            <product>

                <xsl:variable name="test">
                    <xsl:value-of select="color"/>
                </xsl:variable>

                <code><xsl:value-of select="code"/></code>-
                <color><xsl:value-of select="color"/></color>-
                <stock><xsl:value-of select="stock"/></stock>-
                <modelCode><xsl:value-of select="../../ws_code"/></modelCode>-

                <images>
                    <xsl:for-each select="../../images/img_item">
                        <xsl:if test="@type_name = $test">
                            <image><xsl:value-of select="."/></image>
                        </xsl:if>
                    </xsl:for-each>
                </images>
            </product>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Result XML Document:

<?xml version="1.0" encoding="utf-8"?>
<products>
    <product>
        <code>6675</code>
        <color>BLACK</color>
        <stock>3</stock>
        <modelCode>61W9232-MZ</modelCode>
        <image>black-1.jpg</image>
        <image>black-2.jpg</image>
        <image>black-3.jpg</image>
        <image>black-4.jpg</image>
    </product>
    <product>
        .
        .
        .
    </product>
</products>

I need this XML Document:

<?xml version="1.0" encoding="utf-8"?>
<products>
    <product>
        <code>6675</code>
        <color>BLACK</color>
        <stock>3</stock>
        <modelCode>61W9232-MZ</modelCode>
        <image1>black-1.jpg</image1>
        <image2>black-2.jpg</image2>
        <image3>black-3.jpg</image3>
        <image4>black-4.jpg</image4>
    </product>
    <product>
        .
        .
        .
    </product>
</products>

Upvotes: 1

Views: 68

Answers (3)

Parfait
Parfait

Reputation: 107567

Reconsider position() which changes context within the <xsl:for-each>, relative to items in the for-each mapping and not original node position in tree.

Similar to @zx485's answer for generating element name, consider this adjusted XSLT script without the identity transform or <xsl:if> and using ancestor::* with indentation and strip space for pretty print output.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:param name="maxEventNum" select="0"/>

  <xsl:template match="/products/product">
    <products>
      <xsl:apply-templates select="subproducts"/>
    </products>
  </xsl:template>

  <xsl:template match="subproducts">
    <xsl:apply-templates select="subproduct[stock &gt; $maxEventNum]"/>
  </xsl:template>

  <xsl:template match="subproduct">
    <xsl:variable name="curr_color" select="color"/>
    <product>
      <xsl:copy-of select="*"/>
      <modelCode>
        <xsl:value-of select="ancestor::product/ws_code"/>
      </modelCode>
      <xsl:for-each select="ancestor::product/images/img_item[@type_name=$curr_color]">
        <xsl:element name="{concat('image', position())}">
          <xsl:value-of select="."/>
        </xsl:element>
      </xsl:for-each>
    </product>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

madeinevo
madeinevo

Reputation: 33

when I use this code

<image1>black-1</image1>
<image2>black-2</image2>
<image4>black-3</image4>
<image5>black-4</image5>

blue is among the black, image3 is jumping.

<img_item type_name="BLACK">black-1</img_item>
<img_item type_name="BLACK">black-2</img_item>
<img_item type_name="BLUE">blue-1</img_item>
<img_item type_name="BLACK">black-3</img_item>
<img_item type_name="BLACK">black-4</img_item>

Upvotes: 0

zx485
zx485

Reputation: 29022

Change your for-each loop to

<images>
  <xsl:for-each select="../../images/img_item">
    <xsl:if test="@type_name = $test">
      <xsl:element name="{concat('image',position())}">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:if>
  </xsl:for-each>
</images>

This appends the current position to the base element name image.

Upvotes: 2

Related Questions