3

I have an XML file which contains;

<?xml version="1.0"?>
<JobContainer version="2017-1">
  <Object name="MainObject" type="TDM_Container">
    <Object name="OrderList" type="TDM_List_Order">
      <List name="Items">
        <Object type="TDM_Item_Order">
          <Property name="IntOrderID" value="3I-390049-SZEPLOUSKI-793269"/>
        </Object>
      </List>
    </Object>
    <Object name="ModelJobList" type="TDM_List_ModelJob">
      <List name="Items">
        <Object type="TDM_Item_ModelJob">
          <Property name="ModelJobID" value="MJ5393C2FF84844DE38BC481CB5AD36D93"/>
        </Object>
      </List>
    </Object>
        <Object type="TDM_Item_ModelElement">
          <Property name="ModelJobID" value="MJ5393C2FF84844DE38BC481CB5AD36D93"/>
          <Property name="ProcessStatusID" value="psScanned"/>
          <Property name="ProcessLockID" value="plReady"/>
          <Property name="ManufacturingProcessID" value="57435_ManufacturingProcess17"/>
          <Property name="ManufacturerID" value="27606"/>
        </Object>
        <Object type="TDM_Item_ModelElement">
          <Property name="ModelJobID" value="MJ5393C2FF84844DE38BC481CB5AD36D93"/>
          <Property name="ProcessStatusID" value="psClosed"/>
          <Property name="ProcessLockID" value="plReady"/>
          <Property name="ManufacturingProcessID" value="27606_ManufacturingProcess8"/>
          <Property name="ManufacturerID" value="27606"/>
        </Object>
        <Object type="TDM_Item_ModelElement">
          <Property name="ModelJobID" value="MJ5393C2FF84844DE38BC481CB5AD36D93"/>
          <Property name="ProcessStatusID" value="psScanned"/>
          <Property name="ProcessLockID" value="plReady"/>
          <Property name="ManufacturingProcessID" value="57435_ManufacturingProcess17"/>
          <Property name="ManufacturerID" value="27606"/>
        </Object>
      </List>
    </Object>
    <Object name="ElementList" type="TDM_List_Element">
      <List name="Items">
        <Object type="TDM_Item_Element">
          <Property name="Anatomical" value="False"/>
        </Object>
      </List>
    </Object>
  </Object>
</JobContainer>

I need to find the the ManufacturingProcessID property with value = "27606_ManufacturingProcess8", and if I find it then look at the ProcessStatusID property under the same node, and if the value = "psClosed" then I need to move the xml file to another folder.

My code below worked, but it only worked when the node was the first. But sometimes the node is not the first node. How do I find this node if it is not the first node.

Get-ChildItem $sSourceFolder | ForEach-Object -Process {
    if ($_.PSIsContainer)
    {
       # Store subfolder path in a variable
       $sFolderPath = $_.FullName
       $sFolderName = Split-Path $sFolderPath -Leaf

       Get-ChildItem $sFolderPath | Where {$_.Name -like $sFolderName + '.xml'} | foreach{

         $sFilepath = $_.FullName

         [xml]$xml2 = Get-Content $sFilepath

         $sValueMPI = $xml2.SelectNodes('//Property') | ?{$_.name -eq "ManufacturingProcessID"} | select -First 1 -ExpandProperty value

         if ($sValueMPI -eq '27606_ManufacturingProcess8')
         {

           $sValue = $xml2.SelectNodes('//Property') | ?{$_.name -eq "ProcessStatusID"} | select -First 1 -ExpandProperty value

           if ($sValue -eq 'psClosed')
           {

             # If destination folder already exists, add sequential suffix like (1), (2), etc.
             if (Test-Path ($sDestFolder + $sFolderName))
             {
                $j = 1
                While (Test-Path ($sDestFolder + "$sFolderName($j)"))
                {
                   $j = $j + 1
                }
                $sFolderName = "$sFolderName($j)"
             }

             # Move folder to archive destination
             Move-Item $sFolderPath ($sDestFolder + $sFolderName) -ErrorVariable MoveError -Verbose -Force *>> $sLogPath
             if (!($MoveError)) {$i = $i + 1} #if no move error,  then increment counter
           }
         }

       }
    }
}

2 Answers 2

1

you should rather look for parent node and digging deeper into it. Not sure how your XML file looks as you didn't post the valid code above. But let say that it looks like the one below

<Object type="TDM_Item_ModelElement">
  <Property name="ModelElementID" value="MEC35A1D182F984AE893952151DA417D51"/>
  <Property name="ModelJobID" value="MJ5393C2FF84844DE38BC481CB5AD36D93"/>
  <Property name="MaterialID" value="26167_Ti (xyz)"/>
  <Property name="ColorID" value=""/>
  <Property name="ProcessStatusID" value="psClosed"/>
  <Property name="AltProcessStatusID" value="psClosed"/>
  <Property name="ProcessLockID" value="plReady"/>
  <Property name="ManufacturingProcessID" value="27606_ManufacturingProcess8"/>
  <Property name="ManufacturerID" value="27606"/>
</Object>

then the code which will identify if there are any 'Object' nodes having Property element with Name "ManufacturingProcessID" set to Value "27606_ManufacturingProcess8" while in the same node the property with Name "ProcessStatusID" set to Value "psClosed" is following. Wrote it as a one-liner, so it's a bit messy to read, but what it does is that it looks through $xml2 content looking for parent element "Object" where all "Property" elements are nested and then it checks if properties with above mentioned names are having desired values. If there is at least one node found, then you hit the XML file you would like to have archived or what ;)

$validNodes = $xml2 | Select-Xml -XPath '//Object' | %{$_ | ?{((($_.Node.Property.Name -eq "ManufacturingProcessID") -and ($_.Node.Property.Value -eq "27606_ManufacturingProcess8")) -and (($_.Node.Property.Name -eq "ProcessStatusID") -and ($_.Node.Property.Value -eq "psClosed")))}}
if ($validNodes.Count -gt 0) { ... Do your file operation ....}

Hope it helps!

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you Stanislav. It works perfectly. Can you explain the "%{$_" and the "?" syntax of the 3rd and 4th pipeline operation?
@Joe % is a default alias to the ForEach-Object command. ? is a default alias to the Where-Object command. $_ is an automatic variable which refers to the current item in the pipeline. You should already be familiar with them.
@Bacon Bits. Thanks. I just figured that out. I missed it because I am such a novice at PowerShell, even though I had it in my existing code. That old code was more than a year old, so I forgot.
@Joe Ah, sorry if that came across as rude. I just meant that you should already be familiar with ForEach-Object and Where-Object since you'd used them in your code, not that you should already know the default aliases!
1

Stanislav Castek's answer is on the right track with Select-Xml, which supports XPath queries, but instead of extracting only the higher-level <Object> elements with query //Object for later - slow - processing in the pipeline, you can perform the entire query with a single XPath expression:

# Formulate the XPath query
$xpathQuery = '//Property[@value="{0}"]/../Property[@value="{1}"]' -f
  '27606_ManufacturingProcess8', 'psClosed'

# ...

Get-ChildItem -File $sFolderPath -Filter ($sFolderName + '.xml') |
  Select-Xml $xPathQuery | ForEach-Object {
    $file = $_.Path # full path of the input file
    # Perform the move...
    Write-Verbose -Verbose "Moving $file..."   
  }

Note how Select-Xml accepts file input directly from Get-ChildItem.
The ForEach-Object script block will only be entered for those input files where the XPath query returns a match.

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.