Change the value of an attribute according to the value of another attribute

Discussion in 'XML' started by patrizio.trinchini@googlemail.com, Aug 22, 2006.

  1. Guest

    Hi All,

    I'would like to write an XSL transformation that changes the value of
    the atribute of a given element according to the value of another
    atttribute of the same element.

    For instance, given the following XML file:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="XXX"/>
    <child-element name="BBB" value="XXX"/>
    </parent-element>
    </sample>

    I would obtain the following one:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="AAA_VALUE"/>
    <child-element name="BBB" value="BBB_VALUE"/>
    </parent-element>
    </sample>

    where the value of the 'value' attribute of the first child-element has
    been changed to AAA_VALUE because the value of the 'name' attribute was
    AAA; the value of the 'value' attribute of the second child-element has
    been changed to BBB_VALUE because the value of the 'name' attribute was
    AAA.

    I wrote the following XSLT to do the job:

    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput indent="yes"/>
    <xsl:template match="@*|node()">
    <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template match="child-element[@name='AAA']">
    <xsl:apply-templates select="@*[local-name() != 'value']" />
    <xsl:attribute name="value">
    <xsl:text>AAA_VALUE</xsl:text>
    </xsl:attribute>
    </xsl:template>
    </xsl:stylesheet>

    but it only handles the first child-element; I don't know how to handle
    both the child-element, and possibly more then two, in a single
    transform, is it possible? or maybe I need to chain multiple
    transformations?

    Thanks a lot for your help

    Patrizio
    , Aug 22, 2006
    #1
    1. Advertising

  2. toudidel Guest

    i don't understand what you want as the output of the transformation. get
    some example of xml document and output xml document

    td
    toudidel, Aug 22, 2006
    #2
    1. Advertising

  3. Re: Change the value of an attribute according to the value of anotherattribute

    wrote:


    > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    > version="1.0">
    > <xsl:eek:utput indent="yes"/>
    > <xsl:template match="@*|node()">
    > <xsl:copy>
    > <xsl:apply-templates select="@*|node()"/>
    > </xsl:copy>
    > </xsl:template>
    > <xsl:template match="child-element[@name='AAA']">
    > <xsl:apply-templates select="@*[local-name() != 'value']" />
    > <xsl:attribute name="value">
    > <xsl:text>AAA_VALUE</xsl:text>
    > </xsl:attribute>
    > </xsl:template>


    You could simply use the first template you have plus
    <xsl:template match="child-element/@value">
    <xsl:attribute name="{name()}"><xsl:value-of
    select="concat(../@name, '_VALUE')"/></xsl:attribute>
    </xsl:template>


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
    Martin Honnen, Aug 22, 2006
    #3
  4. Guest

    Martin Honnen wrote:
    > wrote:
    >
    >
    > > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    > > version="1.0">
    > > <xsl:eek:utput indent="yes"/>
    > > <xsl:template match="@*|node()">
    > > <xsl:copy>
    > > <xsl:apply-templates select="@*|node()"/>
    > > </xsl:copy>
    > > </xsl:template>
    > > <xsl:template match="child-element[@name='AAA']">
    > > <xsl:apply-templates select="@*[local-name() != 'value']" />
    > > <xsl:attribute name="value">
    > > <xsl:text>AAA_VALUE</xsl:text>
    > > </xsl:attribute>
    > > </xsl:template>

    >
    > You could simply use the first template you have plus
    > <xsl:template match="child-element/@value">
    > <xsl:attribute name="{name()}"><xsl:value-of
    > select="concat(../@name, '_VALUE')"/></xsl:attribute>
    > </xsl:template>
    >
    >
    > --
    >
    > Martin Honnen
    > http://JavaScript.FAQTs.com/


    Thanks a lot for your suggestion, but maybe the sample XML was not
    very self-explaining, may fault.
    What I would obtain is indeed to transformt an XML like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="anOldValueForAAA"/>
    <child-element name="BBB" value="anOldValueForBBB"/>
    <child-element name="CCC" value="anOldValueForCCC"/>
    ...
    </parent-element>
    </sample>

    Into another XML like the follwoing:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="aNewValue1"/>
    <child-element name="BBB" value="aNewValue2"/>
    <child-element name="CCC" value="aNewValue3"/>
    ...
    </parent-element>
    </sample>

    whose content has been determined according to the following rules:

    FOR EACH child-element
    IF name == AAA THEN value = aNewValue1
    ESLE IF name == BBB THEN value = aNewValue2
    ESLE IF name == CCC THEN value = aNewValue3
    ...

    Thanks again for your help

    Regards,

    Patrizio
    , Aug 22, 2006
    #4
  5. Re: Change the value of an attribute according to the value of anotherattribute

    wrote:


    > whose content has been determined according to the following rules:
    >
    > FOR EACH child-element
    > IF name == AAA THEN value = aNewValue1
    > ESLE IF name == BBB THEN value = aNewValue2
    > ESLE IF name == CCC THEN value = aNewValue3
    > ...


    I see no way then but hardcoding the different cases e.g.
    <xsl:template match="child-element[@name = 'AAA']/@value">
    <xsl:attribute name="{name()}">aNewValue1</xsl:attribute>
    <xsl:template>

    <xsl:template match="child-element[@name = 'BBB']/@value">
    <xsl:attribute name="{name()}">aNewValue2</xsl:attribute>
    <xsl:template>

    <xsl:template match="child-element[@name = 'CCC']/@value">
    <xsl:attribute name="{name()}">aNewValue3</xsl:attribute>
    <xsl:template>
    (plus the identity transformation template, the first one you already had).

    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
    Martin Honnen, Aug 22, 2006
    #5
  6. Re: Change the value of an attribute according to the value of anotherattribute

    Martin Honnen wrote:
    >
    >
    > wrote:
    >
    >
    >> whose content has been determined according to the following rules:
    >>
    >> FOR EACH child-element
    >> IF name == AAA THEN value = aNewValue1
    >> ESLE IF name == BBB THEN value = aNewValue2
    >> ESLE IF name == CCC THEN value = aNewValue3
    >> ...

    >
    >
    > I see no way then but hardcoding the different cases e.g.
    > <xsl:template match="child-element[@name = 'AAA']/@value">
    > <xsl:attribute name="{name()}">aNewValue1</xsl:attribute>
    > <xsl:template>
    >
    > <xsl:template match="child-element[@name = 'BBB']/@value">
    > <xsl:attribute name="{name()}">aNewValue2</xsl:attribute>
    > <xsl:template>
    >
    > <xsl:template match="child-element[@name = 'CCC']/@value">
    > <xsl:attribute name="{name()}">aNewValue3</xsl:attribute>
    > <xsl:template>
    > (plus the identity transformation template, the first one you already had).
    >


    here is a better strategy : a kind of associative array

    <data:values>
    <val name="AAA">aNewValue1</val>
    <val name="BBB">aNewValue2</val>
    <val name="CCC">aNewValue3</val>
    </data:values>
    <xsl:template match="child-element/@value">
    <xsl:attribute name="{name()}">
    <xsl:value-of
    select="document()/*/data:values/val[@name=current()/../@name]"/>
    </xsl:attribute>
    <xsl:template>

    I did it quickly, I hope that there is an "apply template" on the
    attribute, otherwise those defined above won't be invoked

    Don't miss the namespace declaration for the prefix "data" : XSLT
    requires a prefix name at this place of the stylesheet

    --
    Cordialement,

    ///
    (. .)
    --------ooO--(_)--Ooo--------
    | Philippe Poulard |
    -----------------------------
    http://reflex.gforge.inria.fr/
    Have the RefleX !
    Philippe Poulard, Aug 22, 2006
    #6
  7. Re: Change the value of an attribute according to the value of anotherattribute

    In article <44eb096f$0$10167$-online.net>,
    Martin Honnen <> wrote:

    >I see no way then but hardcoding the different cases e.g.
    > <xsl:template match="child-element[@name = 'AAA']/@value">
    > <xsl:attribute name="{name()}">aNewValue1</xsl:attribute>
    > <xsl:template>


    You could use a table. To do this you could use a couple of less
    commonly used features of XSLT:

    - you can put any elements in a stylesheet provided that they
    are in some namespace other than the XSLT namespace;
    - you can refer to the stylesheet itself in a call to the document
    function by using the same-document URI "".

    So you could put elements like this at the top-level of the stylesheet:

    <x:new name="AAA" value="aNewValue1"/>
    <x:new name="BBB" value="aNewValue2"/>
    ...

    (you'll have to declare the prefix "x" of course, with some namespace
    name of your own choosing).

    Then you can look up values in this table by using the document function:

    <xsl:template match="child-element/@value">
    <xsl:copy-of select="document('')//x:new[@name=current()/../@name]/@value"/>
    </xsl:template>

    -- Richard
    Richard Tobin, Aug 22, 2006
    #7
  8. Re: Change the value of an attribute according to the value of anotherattribute

    Richard Tobin wrote:

    > In article <44eb096f$0$10167$-online.net>,
    > Martin Honnen <> wrote:
    >
    >
    >>I see no way then but hardcoding the different cases e.g.


    > You could use a table.


    > <x:new name="AAA" value="aNewValue1"/>
    > <x:new name="BBB" value="aNewValue2"/>


    Yes, Philippe has already suggested the same approach. Nevertheless you
    have to hardcode the different cases in the stylesheet as there seemed
    to be no way to infer the new value from the old one.


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
    Martin Honnen, Aug 22, 2006
    #8
  9. Guest

    Martin Honnen wrote:
    > Richard Tobin wrote:
    >
    > > In article <44eb096f$0$10167$-online.net>,
    > > Martin Honnen <> wrote:
    > >
    > >
    > >>I see no way then but hardcoding the different cases e.g.

    >
    > > You could use a table.

    >
    > > <x:new name="AAA" value="aNewValue1"/>
    > > <x:new name="BBB" value="aNewValue2"/>

    >
    > Yes, Philippe has already suggested the same approach. Nevertheless you
    > have to hardcode the different cases in the stylesheet as there seemed
    > to be no way to infer the new value from the old one.
    >
    >
    > --
    >
    > Martin Honnen
    > http://JavaScript.FAQTs.com/


    Thanks a lot to everyone!

    the hard-coded solution works fine and is enough for what I need at
    this time; also the associative table solution is very valuable and
    I'll add it to my toolbox for the future... when I'll be more
    proficient with XSLT ;-)

    I've only another quick question

    Is it possible to remove one or more elements according to the value of
    an element's attribute; i.e. given the following source XML file:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="XXX"/>
    <child-element name="BBB" value="XXX"/>
    <child-element name="CCC" value="XXX"/>
    <additional-data type="text"/>
    <additional-info type="text"/>
    </parent-element>
    </sample>

    is it possible, changing somewhat the last leg to the above IF - ELSE
    IF switch:

    ...
    ELESE IF name = 'CCC' THEN {
    value = aNewValue3
    remove elements additional-data and additional-info type
    }

    to obtain the following result:

    <?xml version="1.0" encoding="UTF-8"?>
    <sample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNameSpaceSchemaLocation="sample.xsd">
    <parent-element>
    <child-element name="AAA" value="aNewValue1"/>
    <child-element name="BBB" value="aNewValue2"/>
    <child-element name="CCC" value="aNewValue3"/>
    </parent-element>
    </sample>

    Thanks again for all your support

    Regards,

    Patrizio
    , Aug 22, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Shapper
    Replies:
    0
    Views:
    435
    Shapper
    May 5, 2005
  2. Replies:
    1
    Views:
    3,957
    Thomas Weidenfeller
    Mar 31, 2005
  3. David Segall

    Change content according to host site

    David Segall, Mar 17, 2006, in forum: HTML
    Replies:
    1
    Views:
    361
    Neredbojias
    Mar 17, 2006
  4. Replies:
    3
    Views:
    616
  5. magix

    Change images according to Time

    magix, Mar 5, 2006, in forum: Javascript
    Replies:
    1
    Views:
    73
    Dr John Stockton
    Mar 6, 2006
Loading...

Share This Page