Use XPath to Search XML Nodes by Node Text Value

Alright, another quick lesson in finding XML.

You see, an XML node like this:

<server name="DomainController1"></server>

Uses the name as an attribute. I just wrote a post about how to search XML by node attribute.

But that won’t do you a lick of good against the actual text value of the node.

<server>DomainController1</server>

Totally different beast. The trick here is to use the “text()” method.

$XML | Select-Xml -Xpath '//server[text()="DomainController1"]'

Oh yeah…  That’s the good stuff.

You can also search a few levels down. Here’s a sample from a Remote Desktop Connection Manager file.

<group>
   <properties>
      <expanded>True</expanded>
      <name>DomainControllers</name>
   </properties>
   <logonCredentials inherit="None">
      <profileName scope="File">myDomain\myAccount</profileName>
    </logonCredentials>
    <server>
       <properties>
           <name>DomainController1.myDomain.demo</name>
       </properties>
    </server>
</group>

If I want to get the GROUP node that has the SERVER named DomainController1.myDomain.demo in it… I can do that with XPath and Select-XML.

#This isn't exactly it, but it's a learning step to help you better understand.
$xml | Select-XML -XPath '//group/server/properties/name[text()="DomainController1.MyDomain.demo"]'

This is how to get the name node of the server that is in the group. See how close that is? Aren’t you already learning?

In English, that XPath statement translates to “Give me the NAME node that has the text value of DomainController1.MyDomain.demo, that is the childnode of a node called properties, which is a child of one called server, which is the child of a node called group. AND, that group node could be anywhere in the XML.”

We define outside of the brackets the node we want to receive. We define inside the brackets the evaluations to get there.

Since I want the GROUP node, I am going to stuff everything else inside the brackets.

$xml | Select-XML -XPath '//group[/server/properties/name/text()="DomainController1.Mydomain.demo"]'

Now that returns the group node.  You’re ready to clone the node, update attributes or insert a child node and then save the updated XML object back to the original XML file.

I recognize this might be a little confusing, but it’s a quirky little command. If you’re needing some extra help, leave a note in the comments and I’ll do my best to answer your questions.

Searching XML Nodes By Attribute Name with Select-XML

Any of you say this prayer after you’ve successfully remembered how to filter by the node attribute property with Select-XML and PowerShell?

Dear God. Please let me remember this syntax the next time I’m trying to search an XML file. If you will just spare me the hours of searchig through useless blog posts and references of XPath syntax I swear I’ll be good. I’ll be a better man to those around me; I’ll live like a boy scout forever.

I’ve said it, thought it and prayed it, but I guess God wanted me to just write it down, because I can never remember it when I want to. Luckily for me, I have this blog where I can jot down simple notes like this.

To search XML nodes with an attribute, use a freaking ‘@’ to indicate attribute name

#Any XML will do
[xml]$xml = Get-Content C:\windows\starter.xml

#Find all nodes of type "component"
$xml | Select-Xml -Xpath "//component"

#Find ONLY the nodes of type "component" with an attribute of "name"
$xml | Select-XML -XPath "//component[@name]"

#And ONLY the nodes of type "component" with an attribute "name" with a value of "Microsoft-Windows-themeservice"
$xml | Select-XML -XPath "//component[@name='Microsoft-Windows-themeservice]"

Hope this helps you. If you found this post, it’s going to be a real timesaver for working with XML.