ccherri has asked for the wisdom of the Perl Monks concerning the following question:

I need to change the value of one node/key if another node/key has a particular value. For instance if the Name node = L1 in a channel element, change the value of the voltage node in that same channel element. I have to set the voltage in each channel according to the name value. I don't really care what the original voltage value is and would prefer to ignore it.

<Settings> <Channels> <Channel Name="R1" Voltage="100" Test="1"/> <Channel Name="R2" Voltage="200" Test="0"/> ... <Channel Name="L1" Voltage="400" Test="0"/> <Channel Name="L360" Voltage="120" Test="1"/> </Channels> </Settings>

So I would expect the code to work something like this...

if($root->findnodes('/Settings/Channels/Channel/Name="L1"')){ #<-Chan +nel name = "L1" my ($L1value) = $root->findnodes('/Settings/Channels/Channel/Name="L1 +" @Voltage[.="400"]'); $L1value->setValue(300); }

but that doesnt work. I cant figure out how to change the voltage based on the value of Name.

Thanks Monks C

Replies are listed 'Best First'.
Re: how to change node value based on other node value
by choroba (Cardinal) on Apr 08, 2015 at 00:58 UTC
    Using XML::XSH2, a less verbose wrapper around XML::LibXML:
    open file.xml ; set /Settings/Channels/Channel[@Name='L1']/@Voltage 300 ; save :b ;
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Choroba, thanks. Your syntax gave me a clue that leads to a solution (XSH2 is not in the ppm library for Activestate and since it took almost all day to load LibXML I am reluctant to go down that path). Here is my solution, albeit a little more verbose...the syntax is at least obvious which is a benefit for simpletons like myself!

      my ($value) = $root->findnodes('/Settings[1]/Channels[1]/Channel[@Name +="Ln"]/@Voltage '); $value->setValue($new_voltage);}

      So now my question is, does the above get me into any trouble??? Thanks Again Chris

Re: how to change node value based on other node value
by Anonymous Monk on Apr 08, 2015 at 00:33 UTC

    but that doesnt work. I cant figure out how to change the voltage based on the value of Name.

    "doesn't work" isn't diagnostic ... :)

    but, even in xpath, you can't make syntax up :) grab xpather.pl and see what it spits out

    /Settings/Channels/Channel[4] # posy /Settings[1]/Channels[1]/Channel[4] # star /*[ local-name() = "Settings" and position() = 1 ] /*[ local-name() = "Channels" and position() = 1 ] /*[ local-name() = "Channel" and @Name = "L360" and @Voltage = "120" and @Test = "1" ] # rats /Settings[1] /Channels[1] /*[ name() = "Channel" and position() = 4 and @Name = "L360" and @Vol +tage = "120" and @Test = "1" ]

    So next step is adjust your xpath to be valid :)

      wow Anonymous Monk, that is cool. But whaddaya mean I can't just make up my own syntax??? Seriously tho, I want to know how this works so I can learn and stop asking newbie questions (been at perl a few years now, xml about a week). So I see #posy and that looks like an xpath and returns (using findnode) an indexed channel (but I don't see how that guarantees it is the channel i want based on name, not index value) and star and rats throw me. I tried all reasonable variations as xpaths and get nothing but errors (invalid expression) or empty results. I see using the //tagname option limits the output to the bits I am interested in but still am not sure what to make of it. Any help or pointers to help is much appreciated. ~Chris

        um, as a path you wrote  '/Settings/Channels/Channel/Name="L1"'

        xpather shows what you should have written

        /Settings[1] /Channels[1] /*[ name() = "Channel" and @Name = "L1"]

        or findnodes( q{ //Channel[ @Name = "L1" and @Voltage = "400" ] } )

Re: how to change node value based on other node value
by Marshall (Canon) on Apr 09, 2015 at 06:21 UTC
    I see this data:
    <Settings> <Channels> <Channel Name="R1" Voltage="100" Test="1"/> <Channel Name="R2" Voltage="200" Test="0"/> ... <Channel Name="L1" Voltage="400" Test="0"/> <Channel Name="L360" Voltage="120" Test="1"/> </Channels> </Settings>
    In general showing code that doesn't work, is not helpful. For the simple fact that by admission, the code is wrong.
    Please show a result that you expect would be accurate.
    I don't see such an expected result.
    Please do that.

      FWIW, AFAICT, OP is trying to change the Voltage from 400 to 300 :)