Tần Quảng
Tần Quảng

Reputation: 117

Create an element if it doesn't exist then move up on an other element

This is the current XML:

<include>
    ...
    <data>
        <id>10001</id>
        <name>Soup</name>
        <minorder>1</minorder>
        <maxorder>5</maxorder>
        <minprice>30</minprice>
        <maxprice>60</maxprice>
        <canSell>1</canSell>
        <isSale>1</isSale>
    </data>
    <data>
        <id>10002</id>
        <name>Noodle</name>
        <minorder>1</minorder>
        <saleprice>45</saleprice>
        <maxorder>3</maxorder>
        <minprice>30</minprice>
        <maxprice>60</maxprice>
        <canSell>1</canSell>
        <isSale>0</isSale>
    </data>
    <data>
        <id>10003</id>
        <name>Shrimp</name>
        <minorder>1</minorder>
        <maxorder>5</maxorder>
        <minprice>30</minprice>
        <maxprice>60</maxprice>
        <canSell>0</canSell>
        <saleprice>45</saleprice>
        <isSale>1</isSale>
    </data>
    ...
</include>

I want to move the entire <saleprice> up above <minprice>. In the case of <saleprice> doesn't exist, we'll create it with the value with <maxprice> / 2.

This is the XSL code that I wrote:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes" omit-xml-declaration="yes" method="xml"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="include/data">
        <xsl:copy>
            <xsl:apply-templates/>
            <xsl:if test="not(saleprice)">
                <saleprice>
                    <xsl:value-of select="format-number(maxprice div 2,'0.#######')"/>
                </saleprice>
            </xsl:if>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

But the results I get now are just creating element <saleprice> if it doesn't exist.

I will be very grateful to the suggestions you give.

Upvotes: 1

Views: 77

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167471

I would let the minprice element trigger the insertion e.g.

<xsl:template match="minprice[not(../saleprice)]">
  <saleprice>
    <xsl:value-of select="format-number(../maxprice div 2,'0.#######')"/>
  </saleprice>
  <xsl:next-match/>
</xsl:template>

and the movement:

<xsl:template match="minprice[../saleprice]">
  <xsl:copy-of select="../saleprice"/>
  <xsl:next-match/>
</xsl:template>

Then add <xsl:template match="data/saleprice"/> to prevent the normal copying by the identity transformation template

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

and your are done i.e. the whole code is

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes" omit-xml-declaration="yes" method="xml"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="minprice[not(../saleprice)]">
      <saleprice>
        <xsl:value-of select="format-number(../maxprice div 2,'0.#######')"/>
      </saleprice>
      <xsl:next-match/>
    </xsl:template>
    
    <xsl:template match="minprice[../saleprice]">
      <xsl:copy-of select="../saleprice"/>
      <xsl:next-match/>
    </xsl:template>
    
    <xsl:template match="data/saleprice"/>
    
</xsl:stylesheet>

Upvotes: 1

Parfait
Parfait

Reputation: 107567

Consider extending out the <xsl:apply-templates> call for explicit ordering of child nodes and handle missing/non-missing saleprice in separate templates:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes" omit-xml-declaration="yes" method="xml"/>
    <xsl:strip-space elements="*"/>
    
    <!-- IDENTITY TRANSFORM TEMPLATE -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- date WITHOUT saleprice  -->
    <xsl:template match="data[not(saleprice)]">
        <xsl:copy>
            <xsl:apply-templates select="id|name"/>
            <!-- Some other elements -->
            <saleprice>
                <xsl:value-of select="format-number(maxprice div 2,'0.#######')"/>
            </saleprice>
            <xsl:apply-templates select="minprice|maxprice"/>
            <!-- Some other elements -->
        </xsl:copy>
    </xsl:template>
    
    <!-- date WITH saleprice  -->
    <xsl:template match="data[saleprice]">
        <xsl:copy>
            <xsl:apply-templates select="id|name"/>
            <!-- Some other elements -->
            <xsl:apply-templates select="saleprice"/>
            <xsl:apply-templates select="minprice|maxprice"/>
            <!-- Some other elements -->
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 2

Related Questions