如果其他节点匹配,则来自另一个文件的PowerShell XML节点值

时间:2019-05-25 18:36:46

标签: xml powershell xml-parsing

我有一个脚本,该脚本基于.csv生成xml文件,该脚本将通过网络服务(RESTapi)充当有效负载。

有效载荷要求我生成一些GUID,只要我生成新的GUID就可以。为了通过API成功更新数据,我需要指定接收系统中每个用户已经存在的GUID。

因此,我要做的第一件事是向系统发出GET请求以导出所有用户。 然后,我根据GET请求中的.xml检查生成的.xml文件中的用户。

如果用户匹配,我想将导出中存在的GUID提取到生成的输出中。这就是我被困住的地方。

例如,我将匹配:

<CVs>
  <CV>
    <GUID></GUID>
    <EMPLOYEE>
        <IDENTIFIER>aa</IDENTIFIER>
    </EMPLOYEE>
  </CV>
</CVs>

反对:

    <CV>
        <GUID>800b96cd-56e9-4587-a9db-41c2a4095d04</GUID>
        <EMPLOYEE>
           <USERNAME>aa</USERNAME>
        </EMPLOYEE>
    </CV>
    <CV>
        <GUID>a07ac517-c7d5-4766-89b6-9101260f6f53</GUID>
        <EMPLOYEE>
           <USERNAME>bb</USERNAME>
        </EMPLOYEE>
    </CV>
    <CV>
        <GUID>84d82720-3e06-4802-9206-69f25b2aa46d</GUID>
        <EMPLOYEE>
           <USERNAME>cc</USERNAME>
        </EMPLOYEE>
    </CV>
  </CVs>

由于“ aa”是一个匹配项,因此我需要以下输出:

<CVs>
  <CV>
    <GUID>800b96cd-56e9-4587-a9db-41c2a4095d04</GUID>
    <EMPLOYEE>
        <IDENTIFIER>aa</IDENTIFIER>
    </EMPLOYEE>
  </CV>
</CVs>

这是我生产所有内容的工作代码,但如果两个节点匹配,则从另一个.xml获取该GUID。

$docTemplate = @'
  <CV>
    <GUID></GUID>
    <EMPLOYEE>
        <IDENTIFIER>$($cert.Identifier)</IDENTIFIER>
    </EMPLOYEE>
    <PAGE id="8">
  $($certs -join "`n")
    </PAGE>
  </CV>
'@

# Per-certificate template.
$entryTemplate = @'
    <RECORD>
      <GUID></GUID>
      <FIELD id="21">
        <DATA>
          <GUID></GUID>
          <VALUE>$($cert.Certificate)</VALUE>
        </DATA>
      </FIELD>
      <FIELD id="36">
        <DATA><VALUE>$($cert.From)</VALUE></DATA>
      </FIELD> 
      <FIELD id="22">$($cert.ExpireDate)
        <DATA><VALUE>$($cert.to)</VALUE></DATA>
      </FIELD>
    </RECORD>
'@

$cvData = Import-Csv demo.csv -Delimiter ';' | Group-Object Identifier -ov grp | ForEach-Object {

  $certs = foreach ($cert in $_.Group) {
    $ExecutionContext.InvokeCommand.ExpandString($entryTemplate)  
  }
  $ExecutionContext.InvokeCommand.ExpandString($docTemplate)
}

$rootTemplate = @'
<CVs>
$($cvData -join "`n")
</CVs>
'@
$output = $ExecutionContext.InvokeCommand.ExpandString($rootTemplate) | Set-Content -LiteralPath 'cvoutput.xml'



#Add GUID
$xmlFile = '.\cvoutput.xml'
[xml]$xmlDoc = Get-Content $xmlFile

#Add Record GUID
foreach ($element in $xmlDoc.CVs.CV.PAGE.RECORD)
{
    [string]$element.GUID = New-Guid
}

#Check if Node exists (certifications require a GUID in the Cert Data Node)
foreach ($element in $xmlDoc.CVs.CV.PAGE.RECORD.FIELD | Where-Object  {$_.name -match "Certifications"}) {
  [string]$element.DATA.GUID = New-Guid
}


$xmlDoc.Save('cv-data.xml')

2 个答案:

答案 0 :(得分:0)

如果我正确地理解了要点,则您想要创建一个新的Guid或使用从包含所有现有用户/ guid列表的XML文件中获取的现有guid。

这是一个有关如何读取文件的最小示例(我在此处使用了此处的字符串代替),将其解析为用户/ guid列表,然后检查接收到的用户是否在现有XML中,以及获取相应的GUID或创建一个新的GUID。

$OutTemplate = @"
<CVs>
  <CV>
    <GUID>{0}</GUID>
    <EMPLOYEE>
        <IDENTIFIER>{1}</IDENTIFIER>
    </EMPLOYEE>
  </CV>
</CVs>
"@

$AllUsers = @"
<CVS>
  <CV>
        <GUID>800b96cd-56e9-4587-a9db-41c2a4095d04</GUID>
        <EMPLOYEE>
           <USERNAME>aa</USERNAME>
        </EMPLOYEE>
    </CV>
    <CV>
        <GUID>a07ac517-c7d5-4766-89b6-9101260f6f53</GUID>
        <EMPLOYEE>
           <USERNAME>bb</USERNAME>
        </EMPLOYEE>
    </CV>
    <CV>
        <GUID>84d82720-3e06-4802-9206-69f25b2aa46d</GUID>
        <EMPLOYEE>
           <USERNAME>cc</USERNAME>
        </EMPLOYEE>
    </CV>
  </CVS>
"@


#   From File 
#   $XML = [xml](Get-Content -Path 'PathToXML.xml' -Raw)

$XML = [xml]$Allusers
$Nodes = $XML.SelectNodes('//CV') | Select @{'Name' = 'EmployeeID' ; 'Expression' = { $_.EMPLOYEE.USERNAME } }, GUID

# Instead of a fixed array, you'd have your received users here.
$Employees = @('aa', 'csd', 'ee')

foreach ($emp in $employees) {
    $Guid = $Nodes | Where EmployeeID -eq ($emp) | Select -First 1
    if ($Guid -eq $null) {
        $Guid = New-Guid
        $Color = 'DarkMagenta'
    }
    else {
        $Color = 'Cyan'
        $Guid = $Guid.Guid
    }

    $OutElement = $OutTemplate -f $guid, $emp

    Write-Host $OutElement -ForegroundColor $Color

}

此示例的重要部分是:

$Nodes = $XML.SelectNodes('//CV') | Select @{'Name' = 'EmployeeID' ; 'Expression' = { $_.EMPLOYEE.USERNAME } }, GUID

从那里,您可以找到现有用户GUID的列表,并且可以针对该列表处理所有记录,并决定是使用现有GUID还是创建新GUID。

答案 1 :(得分:0)

就像 @ sage-pourpre 所示:
$Nodes = $XML.SelectNodes('//CV') | Select @{'Name' = 'EmployeeID' ; 'Expression' = { $_.EMPLOYEE.USERNAME } }, GUID

使用:
foreach ($emp in $xmlDoc.CVs.CV ) { $Guid = $Nodes | Where EmployeeID -eq ($emp.EMPLOYEE.IDENTIFIER) | Select -First 1 [string]$emp.GUID = $Guid.GUID }

解决问题。

谢谢!