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.

wullxz
  • 17,830
  • 8
  • 32
  • 51

3 Answers3

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.

har07
  • 88,338
  • 12
  • 84
  • 137
  • 2
    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 :) – wullxz Apr 01 '15 at 23:09
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'
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
0

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

  • Welcome to SO. It's debatable if this is an answer or a comment; see also http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags for how some folks at SO think about parsing XML with regex :| – Foon Jan 18 '17 at 15:31
  • Yep, more a comment than an answer because it's not even offering a solution but a mere idea. Thanks for your input though. – wullxz Jan 20 '17 at 08:02