access #text property of XMLAttribute in powershell
Asked Answered
M

3

8

I have an xml document formated like this:

<root>
<obj>
   <indexlist>
      <index name="NUMD" value="val1" />
      <index name="DATE" value="val2" />
   </indexlist>
</obj>
</root>

now I'd like to change the value attribute of the index element where name is set to "DATE". I get the attribute like this:

$attr = $xml.selectnodes("//obj/indexlist/index[@name='DATE']/@value")

I can view the value by typing this:

$attr.'#text'

but I can't change it:

$attr.'#text' = 'foo'
The property '#text' cannot be found on this object. Verify that the property exists and can be set.
At line:1 char:1
+ $n.'#text' = 'foo'
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

how do I change the value of an XMLAttribute?


I'd also like to stick with XPath returning the attribute directly if that's possible because the end-user of that script will define the elements and attributes to change in a config file using XPath.
While using XPath for the attributes as well the user can simply provide the attribute to change and the future-value with just two arguments: the XPath and the value.

Morehead answered 25/3, 2015 at 15:15 Comment(0)
P
7

Besides #text, you can also access XmlAttribute's value via Value property :

$attr = $xml.SelectSingleNode("//obj/indexlist/index[@name='DATE']/@value")

#print old value
$attr.Value

#update attribute value 
$attr.Value = "new value"

#print new value
$attr.Value

Note that Value in $attr.Value is property name of XmlAttribute. It doesn't affected by the fact that the attribute in your XML named value.

Portamento answered 26/3, 2015 at 2:49 Comment(1)
actually, the problem was that i used selectnodes instead of selectsinglenode like you did. when i just echo'd my $attr powershell would show me the value of #text every time and also would say the returned type is a XmlAttribute if i did a $attr | gm. but in fact, the returned type seems to be an arrary or collection which - of course - has no value property. using my approach with $attr[0].value instead of $attr.value also works, but it was your answer and use of selectsinglenode that led me into the right direction ;) thanks :)Morehead
F
3

Don't select the attribute, select the node. The attributes of the node will be represented as properties and can be modified as such:

$node = $xml.SelectSingleNode("//obj/indexlist/index[@name='DATE']")
$node.value = 'foo'

Use a loop if you need to modify several nodes:

$nodes = $xml.SelectNodes("//obj/indexlist/index[@name='DATE']")
foreach ($node in $nodes) {
  $node.value = 'foo'
}
Forzando answered 25/3, 2015 at 15:55 Comment(0)
H
0

Of course you could also treat the XMl as a text file and have the namespace declarations removed using SED or such.

Halitosis answered 18/1, 2017 at 15:13 Comment(2)
Welcome to SO. It's debatable if this is an answer or a comment; see also #1732848 for how some folks at SO think about parsing XML with regex :|Chenopod
Yep, more a comment than an answer because it's not even offering a solution but a mere idea. Thanks for your input though.Morehead

© 2022 - 2024 — McMap. All rights reserved.