I have an XML File where root elements have a nested tag to identify the node. How could I grab the node by the specific tag contained within the root element?
Below I have tag named "master", which can contain "old" or "new" value. How could I grab just "new"?
Sample File:
<xml>
<foo>
<master>New</master>
<data>
<val1>Value</val1>
</data>
</foo>
<foo>
<master>Old</master>
<data>
<val1>Value</val1>
</data>
</foo>
</xml>
Select-XML does not work because sometimes the file has tags the are not closed.
With this code, I can get val1 from both nodes
[xml] $xml = Get-Content "$file"
$xml.xml.foo.data
I tried
$xml.xml.foo.data.val1 | Where-Object ($xml.xml.foo.master -eq "New")
and I tried
if ($xml.xml.foo.master -eq "New") {$xml.xml.foo.data.val1}
Sorry if my xml terminology doesn't make sense.
CodePudding user response:
To be clear: if the input XML isn't well-formed (syntactically valid XML), no XML-parsing solution will work - whether via a [xml]
cast or via Select-Xml
.
If your XML is well-formed:
Via [xml]
and PowerShell's adaption of the XML DOM:
$xml.xml.foo.Where({ $_.master -eq 'New' }, 'First')
If you want to find multiple master
elements with text content New
, remove the 'First'
argument.
Via Select-Xml
(pipe to Select-Object -First 1
to limit to one match), if the XML is also valid (well-formed and conforms to referenced schemas - n/a to the sample XML):
(Select-Xml -XPath '/xml/foo[master="New"]' -LiteralPath file.xml).Node
As for using Get-Content
with an [xml]
cast to parse an XML file:
Use
-Raw
withGet-Content
to speed it up.Beware of potentially misreading the XML file - see the bottom section of this answer.