How to get node’s information using compare-object?

Welcome Forums General PowerShell Q&A How to get node’s information using compare-object?

Viewing 4 reply threads
  • Author
    Posts
    • #237397
      Participant
      Topics: 1
      Replies: 2
      Points: 18
      Rank: Member

      I have two xml files which I need to compare and get the differences present from the file. These are huge files
      test1.xml

      <?xml version="1.0" encoding="utf-8"?>
      <Project>
        <Proj Name="ABC">
            <FileName Name="abc">
              <Name name="John" age="20" />
      		<Name name="Carter" age="30" />
            </FileName>
        </Proj>
      </Project>
      

      test2.xml

      <?xml version="1.0" encoding="utf-8"?>
      <Project>
        <Proj Name="ABC">
            <FileName Name="abc">
              <Name name="John" age="20" />
            </FileName>
        </Proj>
      </Project>
      

      When I ran the command

      Compare-Object $(Get-Content C:\test1.xml ) $(Get-Content C:\test2.xml ) -IncludeEqual
      

      I got an output which has the information about the FileName also

      InputObject                            SideIndicator
      -----------                            -------------
      <?xml version="1.0" encoding="utf-8"?> ==           
      <Project>                              ==           
        <Proj Name="ABC">                    ==           
            <FileName Name="abc">            ==           
              <Name name="John" age="20" />  ==           
            </FileName>                      ==           
        </Proj>                              ==           
      </Project>                             ==           
        <Name name="Carter" age="30" />      <=  
      

      Where as when I ran this command, it showed me the difference from test1.xml. But, I also want to know from which FileName

      PS C:\WINDOWS\system32> Compare-Object $(Get-Content C:\test1.xml ) $(Get-Content C:\test2.xml )
      
      InputObject                       SideIndicator
      -----------                       -------------
       <Name name="Carter" age="30" />    <= 
      

      Any suggestion on this? I am very new to powershell.

      Thanks,
      Zahid

    • #237478
      Participant
      Topics: 6
      Replies: 15
      Points: 141
      Rank: Participant

      What are you trying to do once you have the difference?

      If you want to extract the value of the “Name” attribute from the node “FileName”, you will need to parse the information.

      Something like:

      $Comparison = Compare-Object (Get-Content C:\test1.xml) (Get-Content C:\test2.xml) -IncludeEqual
      
      $FilteredResults = $Comparison | Where-Object { $_ -match "<FileName Name=" -or $_.sideindicator -match "<=" }
      
      $FilteredResults.inputobject.trim()

      Will output something like this:

      <FileName Name="abc">
      <Name name="Carter" age="30" />

      But it really depends on how you want the output to displayed/used. What do you want to do next with the information, or how do you want it specifically presented?

    • #237517
      Participant
      Topics: 1
      Replies: 2
      Points: 18
      Rank: Member

      Thanks Phatmandrake for your quick response. Based on the differences in the xml file, I need to run another business logic.
      The code you shared will work only if I have one node available.
      I am going to have a huge xml file with multiple nodes present.

      <?xml version="1.0" encoding="utf-8"?>
      <Project>
        <Proj Name="ABC">
            <FileName Name="abc">
              <Name name="John" age="20" />
            </FileName>
            <FileName Name="xyz">
              <Name name="zahid" age="20" />
            </FileName>
        </Proj>
      </Project>
      

      The output of the code which you have shared will returns all the nodes, if I consider above example

      <FileName Name="abc">
      <FileName Name="xyz">
      <Name name="Carter" age="30" />
      

      But, I need only those FileNames which have the differences.

    • #237601
      Participant
      Topics: 6
      Replies: 15
      Points: 141
      Rank: Participant

      If I am understanding you correctly, then you want to know which Child Nodes of the FileName Nodes are not present in the Difference Object, but you also want to relate that to the Name attribute of the corresponding Filename parent node. If this is the case and you want to be able to actually work with Powershell Objects after the match, then I would convert your text XML to XElement Objects, and turn them into custom objects with the properties you need to examine, then compare those objects to each other.

      [System.Xml.Linq.XElement]$RefObj = @"
      <?xml version="1.0" encoding="utf-8"?>
      <Project>
        <Proj Name="ABC">
          <FileName Name="abc">
            <Name name="John" age="20" />
          </FileName>
          <FileName Name="xyz">
            <Name name="zahid" age="20" />
          </FileName>
        </Proj>
      </Project>
      "@
      
      [System.Xml.Linq.XElement]$DiffObj = @"
      <?xml version="1.0" encoding="utf-8"?>
      <Project>
        <Proj Name="ABC">
          <FileName Name="abc">
            <Name name="John" age="20" />
          </FileName>
          <FileName Name="xyz">
            <Name name="zahid" age="20" />
            <Name name="Jacob" age="20" />
          </FileName>
        </Proj>
      </Project>
      "@
      
      function XMLObject {
      
         param($XML)
      
         process{
            $_.Descendants("FileName").foreach{
               $_.nodes().foreach{
                  [PSCustomObject]@{
                       "FileName"=$_.parent.attribute("Name").value
                       "Name"=[PSCustomObject]$_.attributes()
                  }
               }
            }
         }
      }
      
      Compare-Object ($RefObj | XMLObject) ($DiffObj | XMLObject) -Property Filename, Name
      
      Output:
      
      Filename Name                     SideIndicator
      -------- ----                     -------------
      xyz      {name="Jacob", age="20"} =>
      
      
      Compare-Object ($RefObj | XMLObject) ($DiffObj | XMLObject) -Property Filename,Name -IncludeEqual                    
                  
      Output:
      
      Filename Name                     SideIndicator
      -------- ----                     -------------
      abc      {name="John", age="20"}  ==
      xyz      {name="zahid", age="20"} ==
      xyz      {name="Jacob", age="20"} =>

      It’s important to note that when you use Compare-Object it simply looks for any identical matches, regardless of position unless you specify the SyncWindow parameter, which will then enforce position based comparison.

      Compare-Object Docs

      Compare-Object examines adjacent objects when it doesn’t find the object in the same position in a collection. The default value is [Int32]::MaxValue, which means that Compare-Object examines the entire object collection.

      I don’t know what other restraints you may be looking for in comparing the differences between your XML, but if you’re just looking to see which child nodes do not exist for parent nodes of type `FileName’, then the code above should work for you.

      • This reply was modified 3 weeks, 1 day ago by Phatmandrake. Reason: Grammar
    • #238193
      Participant
      Topics: 1
      Replies: 2
      Points: 18
      Rank: Member

      Thanks Phatmandrake. I think this will help me.

Viewing 4 reply threads
  • You must be logged in to reply to this topic.