【问题标题】:Powershell XML select node with particular value具有特定值的 Powershell XML 选择节点
【发布时间】:2018-02-09 20:00:34
【问题描述】:

我有一个 XML 文件,其中包含;

<?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>

我需要找到 value = "27606_ManufacturingProcess8" 的 ManufacturingProcessID 属性,如果找到它,则查看同一节点下的 ProcessStatusID 属性,如果 value = "psClosed" 则我需要移动 xml 文件到另一个文件夹。

我下面的代码有效,但它仅在节点是第一个时有效。但有时节点不是第一个节点。如果不是第一个节点,如何找到这个节点。

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
           }
         }

       }
    }
}

【问题讨论】:

    标签: powershell xml-parsing


    【解决方案1】:

    您应该寻找父节点并深入挖掘它。由于您没有发布上面的有效代码,因此不确定您的 XML 文件的外观。但是假设它看起来像下面的那个

    <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>
    

    然后代码将识别是否有任何“对象”节点的属性元素的名称“ManufacturingProcessID”设置为值“27606_ManufacturingProcess8”,而在同一节点中名称“ProcessStatusID”的属性设置为值“psClosed”是下列的。把它写成单行的,所以读起来有点乱,但它的作用是通过 $xml2 内容查找所有“属性”元素都嵌套的父元素“对象”,然后检查属性是否具有上述名称具有所需的值。如果找到至少一个节点,那么您点击您想要存档的 XML 文件或其他文件;)

    $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 ....}
    

    希望对你有帮助!

    【讨论】:

    • 谢谢斯坦尼斯拉夫。它完美地工作。你能解释一下“%{$_”和“?”第三和第四流水线操作的语法?
    • @Joe %ForEach-Object command 的默认别名。 ?Where-Object command 的默认别名。 $_ is an automatic variable 指管道中的当前项目。您应该已经熟悉它们了。
    • @Bacon Bits。谢谢。我只是想通了。我错过了它,因为我是 PowerShell 的新手,即使我在现有代码中有它。那个旧代码已经有一年多了,所以我忘记了。
    • @Joe Ah,对不起,如果这显得粗鲁。我的意思是您应该已经熟悉 ForEach-ObjectWhere-Object,因为您在代码中使用过它们,而不是您应该已经知道默认别名!
    【解决方案2】:

    Stanislav Castek's answerSelect-Xml 走在正确的轨道上,它支持 XPath 查询,但不是只提取更高级别的 &lt;Object&gt; 元素和查询 //Object 供以后使用 - 慢- 在管道中处理,您可以使用单个 XPath 表达式执行整个查询

    # 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..."   
      }
    

    注意Select-Xml 如何直接从Get-ChildItem 接受文件输入。
    ForEach-Object 脚本块只会为那些 XPath 查询返回匹配的输入文件输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-20
      相关资源
      最近更新 更多