2

I am looking for a way to have a powershell search through an XML doc searching for a specific ID that's within an "ID" tag, then locate the very next tag and replace it's value with "true". The IDs would be provided by the first column of a csv file. Here is an example of the XML structure:

<primary>
<main>
<id>47</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
<primary>
<main>
<id>48</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
<primary>
<main>
<id>49</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
<primary>
<main>
<id>50</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
<primary>
<main>
<id>51</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>

Now imagine the csv file has, in column 1:

47
49

I would like only those indicator flag tags to be updated to true.
Any help would be very appreciated!!

3
  • Just for clarity: when I said "the very next tag" I mean the very next <indicatorflag> tag. I've attempted a regex find and replace, but it selects the last <indicatorflag> tag in the entire doc rather than the one within the same <primary> tag as the located ID Commented May 8, 2020 at 17:59
  • Your XML is invalid because it is missing a root element. Also, the csv with the id's to look for looks like a simple text file where each id is on a new line. Is that the actual format of the file? Commented May 8, 2020 at 18:00
  • yes it is in that format, exactly Commented May 8, 2020 at 18:25

2 Answers 2

2

First thing: Don't use regex replace on xml. PowerShell is very able to handle (valid) XML.

As commented, the XMLyou show is invalid as it is missing a root element.
After fixing the XML by encompassing it all inside a <root>...</root> element, you can read this in like this:

[xml]$xml = Get-Content -Path 'D:\Test\input.xml' -Raw

Next, read the file to get the id's to update. If this file is like you show us, a text file where each id is on its own new line, use this:

$ids = Get-Content -Path 'D:\Test\ids.txt'

If however, this file IS a CSV file, something like

"ID","Something"
"47","Whatever"
"49","Anything"

then read the ids as array from it using:

$ids = (Import-Csv -Path  'D:\Test\ids.csv').ID

You can now loop over the id's and change the value of the belonging <indicatorflag> tag:

foreach ($id in $ids) {
    ($xml.root.primary.main | Where-Object {$_.id -eq $id}).indicatorflag = 'true'
}

# save the updated XML
$xml.Save('D:\Test\output.xml')
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you SO much! This all makes sense. I'll give it a try right now
2

You can use the following XPath expression to find the <indicatorflag> node that's a sibling following the <id>49</id> node:

//id[. = 49]/following-sibling::indicatorflag

Generalize and use either Select-Xml or the XmlDocument.SelectSingleNode() method to obtain the nodes:

$xml = [xml]@'
<root>
<primary>
<main>
<id>48</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
<primary>
<main>
<id>49</id>
<desc>foobar</desc>
<indicatorflag>false</indicatorflag>
</main>
</primary>
</root>
'@

foreach($ID in 48,49){
  $ifNode = $xml.SelectSingleNode("//id[. = $ID]/following-sibling::indicatorflag")
  if($ifNode){
    $ifNode.InnerText = "false"
  }
}

$xml.Save("C:\path\to\output.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.