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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.