0

I have some XML that I want to be able to overwrite the STATUS tag.

how it looks:

<START>
  <EXAMPLE>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
  </EXAMPLE>
</START>

How I want it to look:

<START>
  <EXAMPLE>
    <THINGS>
      <STUFF>
        <STATUS>Open</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>NA</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Closed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Open</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>Open</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
      <STUFF>
        <STATUS>NA</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
  </EXAMPLE>
</START>

With this code I am able to change each of the STATUS tags to the correct value, when I check the console after running just $XMLStatus after the script has run it shows everything as it should, but not when I open the XML in notepad. It still shows everything as Not_Reviewed. I am not sure what I am doing wrong here and any help is greatly appreciated.

[xml]$xmldoc = Get-Content -Path 'C:\test.xml'
$XMLStatus = $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS
$XMLcount = 0
       foreach($one in $XMLStatus[$XMLcount]){           
            foreach($status in $one){
                $one = $myvalue
                Switch ($one){
                    1 {$status = "Open"; break;}
                    2 {$status = "Closed"; break;}
                    3 {$status = "NA"; break;}
                    default {"Open"}
                }
                $XMLStatus[$XMLcount] = $status
            }
        }
        
$xmldoc.Save('C:\test.xml')
$XMLcount++
1
  • 1
    First, your xml sample is invalid. Second, your contrived example seems erroneous in several ways. Third, even if $XMLStatus gets updated, it has no bearing on the $xmldoc, you never write anything back to it. Please update your code with working example. As it stands $XMLStatus still contains only Not_Reviewed Commented Oct 22, 2020 at 17:04

2 Answers 2

1

There's no need to access individual elements via indexes. Use an XPath query to select all the STATUS elements into an XPathNodeList. Iterate it with a foreach loop and change InnerText property with a switch statement. Like so,

[xml]$xmldoc = get-content c:\whatever.xml

# Select all STATUS elements. NB: element names in XPath are case-sensitive
$nl = $xmldoc.selectnodes('/START/EXAMPLE/THINGS/STUFF/STATUS')

# Loop through the nodes and change InnerText numbers to string values
foreach($n in $nl) {
    switch($n.InnerText){
      1 {$s = "Open"; break;}
      2 {$s = "Closed"; break;}
      3 {$s = "NA"; break;}
      default {$s = "Open"}
    }
    $n.InnerText = $s
}
# Print the results on console
$xmldoc.Save([console]::out)
Sign up to request clarification or add additional context in comments.

Comments

0

Don't really work with xml in PowerShell too often, but I think I see what's up.

Your xml was copy-pasted funny, and made it invalid. You're missing some tags.

Because of this I took some liberties and made my own.

<START>
  <EXAMPLE>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
  </EXAMPLE>
</START>

First, the reason you're not seeing the values change in the file, is because you're not saving those changes to the file. You're putting the value of $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS into a variable, then your working with that variable, and only making changes to the variable, instead of the original doc variable.

Second, $myvalue wasn't set anywhere in your example, so everything would just default to your default case in your switch.

third, your default case doesn't do anything except print "open" to stdout.

last, you'll want to avoid trying to change the value by getting the value of the object, and changing that value. I know that sounds confusing, so let's work through an example.

What we think we want to modify, is the value of $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS[i] but that's where we're mistaken. We don't want to set the value of .STATUS[i], because all that is, is just a string object, which you can see when you run this, and look at TypeName.

$xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS[0] | Get-Member

What we actually want to modify, is the STATUS property, that resides in the STUFF element. So if you do this

$xmldoc.START.EXAMPLE.THINGS.STUFF[0] | Get-Member

You'll notice that the TypeName is System.Xml.XmlElement and there's a property there called STATUS and in the definition column, we see that it is a string, and we know we can both get this value, and set it {get;set;} for reference, these are called getters and setters.

In order to modify that value we'll need to set the STATUS property like this ``$xmldoc.START.EXAMPLE.THINGS.STUFF[0].STATUS = "whatever"`

So after some modifications, this is what I came up with. The comments are where I made changes.

[xml]$xmldoc = "
<START>
  <EXAMPLE>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
  </EXAMPLE>
</START>"

#set myyvalue

$myvalue = 1
# removed this var completely
#$XMLStatus = $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS
$XMLcount = 0
# for the foreach, we want to work with each object in the STUFF array
# I also removed the extra foreach, as it seemed unnecessary
foreach($one in $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS)
{
# made the switch, switch off of $myvalue           
    Switch ($myvalue){
        1 {$status = "Open"; break;}
        2 {$status = "Closed"; break;}
        3 {$status = "NA"; break;}
# fixed the default case to properly set the var
        default {$status = "Open"}
    }
    $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS = $status
}        
   
$xmldoc.Save('C:\temp\test.xml')
$XMLcount++

And if you want a version that iterate through everything via running it once, you can get the length of STUFF and use a while loop

[xml]$xmldoc = "
<START>
  <EXAMPLE>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
    <THINGS>
      <STUFF>
        <STATUS>Not_Reviewed</STATUS>
        <DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
      </STUFF>
    </THINGS>
  </EXAMPLE>
</START>"


$myvalue = 1
$numberOfElements = $xmldoc.START.EXAMPLE.THINGS.Length
$XMLcount = 0
while($XMLcount -lt $numberOfElements)
{
    foreach($one in $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS)
    {           
        Switch ($myvalue){
            1 {$status = "Open"; break;}
            2 {$status = "Closed"; break;}
            3 {$status = "NA"; break;}
            default {$status = "Open"}
        }
        $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS = $status
    }
    $XMLcount++        
} 
$xmldoc.Save('C:\temp\test.xml')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.