35

I am trying to access and change the particular attribute from XML tag

XML:

<office>
  <staff branch="Hanover" Type="sales">
    <employee>
        <Name>Tobias Weltner</Name>
        <function>management</function>
        <age>39</age>
    </employee>
    <employee>
        <Name>Cofi Heidecke</Name>
        <function>security</function>
        <age>4</age>
    </employee>
  </staff>
  <staff branch="London" Type="Technology">
   <employee>
    <Name>XXXX</Name>
    <function>gement</function>
    <age>39</age>

From the above example I want to print branch attribute and then want to change it with one value such as New York in all the whole XML and using below code to do that

       $xml=New-Object XML

      $xml.Load("C:\FE6Work.xml")

      $node=$xml.SelectNodes("/office/staff")

      write-output $node.branch
      $node.branch="New York"

But get an error stating can't find the element.

Can someone please help?

love thakker
  • 460
  • 2
  • 13
  • 29
user3759904
  • 875
  • 2
  • 8
  • 7
  • Possible duplicate of [How can I update the value for a XML node using PowerShell?](http://stackoverflow.com/questions/3202567/how-can-i-update-the-value-for-a-xml-node-using-powershell) – Unsigned Feb 23 '17 at 18:43

3 Answers3

57

Try the following:

$nodes = $xml.SelectNodes("/office/staff");
foreach($node in $nodes) {
    $node.SetAttribute("branch", "New York");
}

This will iterate through all nodes returned by SelectNodes() and modify each one.

PeterK
  • 3,667
  • 2
  • 17
  • 24
  • @user3759904: Did you type it as 'setAttribute' or 'SetAttribute' (it should be the latter, it's case-sensitive)?. If you did type it with the correct casing, what happens exactly (e.g. you get an error or the attribute doesn't change)? – PeterK Jul 10 '14 at 15:07
  • Method invocation failed because [System.Xml.XPathNodeList] doesn't contain a method named 'SetAttribute'. – user3759904 Jul 10 '14 at 15:23
  • @user3759904: You're probably using a different PowerShell version, I have tested with 4.0 and it works flawlessly using your code and input. In any case, I have edited my answer with a longer version, that should work in earlier PowerShell versions as well. – PeterK Jul 10 '14 at 15:31
  • ok thanks for quick reply. One more thing. I am trying to access first three chrachter from the branch atttribute value using below code $foldername=$xml.Office.Staff | Select branch | Substring(2) getting below error The term 'Substring' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again – user3759904 Jul 10 '14 at 15:37
  • I've got powershell 2.0 :( – user3759904 Jul 10 '14 at 15:45
  • `$foldername = $xml.Office.Staff | Select-Object { $_.branch.Substring(0, 3) }` should work in any PowerShell version I think. – PeterK Jul 10 '14 at 15:47
  • Thanks last thing I am trying to concatinate the output $folders=$xml.office.staff | = 'PROD_' + Select-Object { $_.branch.Substring(2)} getting below error You must provide a value expression on the right-hand side of the '+' operator. At line:17 char:54 Expressions are only allowed as the first element of a pipeline. At line:17 char:56 Unexpected token 'Select-Object' in expression or statement. At line:17 char:56 – user3759904 Jul 10 '14 at 16:02
  • @user3759904: Your concatenation should go in the script block, e.g. `$foldername = $xml.Office.Staff | Select-Object { "PROD_" + $_.branch.Substring(0, 3) }`. – PeterK Jul 10 '14 at 16:06
  • is there any alternative of SetAttribute as I dont think so upgrade would be an option for me, as I want to set the new concat value to the attribute branch – user3759904 Jul 10 '14 at 16:07
  • You should be able to use the code in my edited answer (the edit I made 45 mins ago) even in earlier PowerShell versions. Did you try that? It does not use SetAttribute(), but a simple `foreach` loop to iterate through the elements. – PeterK Jul 10 '14 at 16:14
  • Cannot set "branch" because only strings can be used as values to set XmlNode properties. – user3759904 Jul 10 '14 at 16:18
  • I did try $node.branch = '"' + $folders + '"'; ending its written &quote; &quote; in a file – user3759904 Jul 10 '14 at 16:27
  • Ok, this appears to be a PowerShell 2.0 bug as per: http://stackoverflow.com/questions/10355578/why-is-powershell-telling-me-a-string-is-not-a-string-and-only-when-calling-str. I've edited my answer once again to use SetAttribute(). This should work, because it will be applied on individual nodes and SetAttribute() goes back a long way. You won't be needing the double-double quotes. – PeterK Jul 10 '14 at 16:29
  • thanks for your help on this, getting an error on xml.Save($path) any idea on this would be very helpful Multiple ambiguous overloads found for "Save" and the argument count: "1". – user3759904 Jul 11 '14 at 09:03
  • that is sorted but its writting a blank value in XML attribute – user3759904 Jul 11 '14 at 09:16
  • $folders=$xml.office.Staff | Select-Object{ $FolderNameInitial + $_.branch.Substring(4)} $nodes=$xml.SelectNodes("/office/staff") foreach($node in $nodes) { if($node -eq $null) { write-output "Atrribute/Property not found" } else { $node.SetAttribute("branch",$folders) } } $xml.Save($path) – user3759904 Jul 11 '14 at 09:23
  • Ok, you mixed up two different approaches here and this is also way out of the scope of the original question. Here's a semi-complete script that replaces the "branch" attribute with "PROD_" + the first 3 characters of the branch name. `$nodes = $xml.SelectNodes("/office/staff") foreach($node in $nodes) { $folders = "PROD_" + $node.branch.Substring(0, 3) $node.SetAttribute("branch", $folders); }` – PeterK Jul 11 '14 at 10:16
  • You are superstar...Thanks for your help dude – user3759904 Jul 11 '14 at 10:25
  • 2
    Dude, this is awesome! I wrote this big fancy UI and thought I'd have to scrap the whole thing, because I couldn't figure out how to change XML values. +1, awesome, you rock. – FoxDeploy Apr 14 '15 at 17:54
  • 1
    @PeterK, I can't edit your post (too short edit), branch string is missing double quotes at the end. – Richard Dally Aug 25 '15 at 12:24
  • @LeFlou: Thank you, I have added the missing double quote. – PeterK Aug 25 '15 at 12:28
12

You can access the attributes directly in the [xml] object like this:

# C:\temp> $xml = [xml](Get-Content C:\FE6Work.xml)
# C:\temp> $xml.office.staff

branch                   Type                           employee                                                             
------                   ----                           --------                                                             
Hanover                  sales                          {Tobias Weltner, Cofi Heidecke}                                      
London                   Technology                     {XXXX, Cofi}                                                         

# C:\temp> $xml.office.staff | foreach{$_.branch = "New York"}
# C:\temp> $xml.office.staff

branch                   Type                           employee                                                             
------                   ----                           --------                                                             
New York                 sales                          {Tobias Weltner, Cofi Heidecke}                                      
New York                 Technology                     {XXXX, Cofi}                                                         
zdan
  • 28,667
  • 7
  • 60
  • 71
  • thanks for your help on this, getting a below error on xml.Save($path) any idea on this would be very helpful Multiple ambiguous overloads found for "Save" and the argument count: "1". – user3759904 Jul 11 '14 at 09:04
  • Ignore that its sorted – user3759904 Jul 11 '14 at 09:15
  • when i am updating file its writing blank values in the xml such as branch set to " " updated code is $folders=$xml.office.Staff | Select-Object{ $FolderNameInitial + $_.branch.Substring(4)} $nodes=$xml.SelectNodes("/office/staff") foreach($node in $nodes) { if($node -eq $null) { write-output "Atrribute/Property not found" } else { $node.SetAttribute("branch",$folders) } } $xml.Save($path) – user3759904 Jul 11 '14 at 09:20
4

if we are taking attribute from console and changing its value ?

$path=Read-Host -Prompt 'Enter path of xml file'
[xml]$xmldata = get-content "$path"

$tag = Read-Host -Prompt 'Enter tag'
$value = Read-Host -Prompt 'Enter value'
$xmldata.InstallConfig.$tag="$value"
$xmldata.Save($path)