2017-02-02 7 views
0

소스 XML 파일이 있는데 사용 된 AddressType이 응용 프로그램에서 사용되는 것과 일치하는지 확인해야합니다. AddressType이 앱에 정의 된 것과 일치하면 모든 것이 정상이며 아무 것도하지 않습니다. 그러나 AddressType이 일치하지 않으면 XML 파일에서 전체 공급자를 삭제하십시오. rest 메소드를 통해 앱에서 유형 코드를 다시 가져 와서 배열에 넣습니다. 비교가 정상적으로 작동합니다. 공급자를 제거 할 때 문제가 발생합니다. 첫 번째 공급자는 xml 파일에서 제거되었지만 나머지 공급자는 제거되지 않습니다.Powershell - xml removeall & looping

다음은 앱의 형식 코드입니다.

HQ 
MAIN 
NOT_STATED 
OP 

그리고 이것은 샘플 XML 파일 샘플 XML 파일에 따라서

<?xml version="1.0" encoding="UTF-8"?> 
<OrganisationUnits> 
    <OrganisationUnitsRow num="1"> 
    <OrganisationId>ID1</OrganisationId> 
    <OrganisationName>PROVIDER_1</OrganisationName> 
    <Addresses> 
     <AddressesRow num="1"> 
     <AddressType>TYPE1A</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
     <AddressesRow num="2"> 
     <AddressType>TYPE1B</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
    </Addresses> 
    </OrganisationUnitsRow> 

    <OrganisationUnitsRow num="2"> 
    <OrganisationId>ID2</OrganisationId> 
    <OrganisationName>PROVIDER_2</OrganisationName> 
    <Addresses> 
     <AddressesRow num="1"> 
     <AddressType>TYPE2A</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
     <AddressesRow num="2"> 
     <AddressType>TYPE2B</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
    </Addresses> 
    </OrganisationUnitsRow> 

    <OrganisationUnitsRow num="3"> 
    <OrganisationId>ID3</OrganisationId> 
    <OrganisationName>PROVIDER_3</OrganisationName> 
    <Addresses> 
     <AddressesRow num="3"> 
     <AddressType>TYPE3A</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
    </Addresses> 
    </OrganisationUnitsRow> 

</OrganisationUnits> 

내가 5 개 인 AddressType 라인이에게있는 응용 프로그램에서 유형을하여 모든 일치하지 않는 (3 개 개의 다른 업체에서 확산) 3 제공자는 삭제해야합니다.

그리고 이것은 내 코드 조각입니다.

#Define the source XML file path 
$XMLPath = "$Provider_Root\TEST\source5.xml" 
$xml = [xml](Get-Content $XMLPath) 

## username and password to be used for web application login 
$acctname = 'user1' 
$password = 'letmein' 

$params = @{uri = 'http://localhost:8080/providers/settings/provider/providerAddressTypes'; 
        Method = 'Get'; #(or POST, or whatever) 
        Headers = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($acctname):$($password)")); 
      } #end headers hash table 
    } #end $params hash table 

# This gets all the basic info ok 
$var = invoke-restmethod @params 

#show the values in the console 
echo $var.code 

#The app returns the following codes 
# HQ 
# MAIN 
# NOT_STATED 
# OP 


#echo $var.Length 
$total = $var.Length 
write-host "AddressType records in application = $total" 

#Count the number of AddressTypes that we are getting back from the app via the web call, if it is greater than zero, then we are getting data back ok. 
if ($var.Length -gt 0) 
{ 

    #Loop through the XML file looking for the AddressRow 
    foreach($AddressRow in $xml.OrganisationUnits.OrganisationUnitsRow.Addresses.AddressesRow) 
    { 

     #Get the organisation ID - used for reporting purposes 
     $OrgID = $xml.OrganisationUnits.OrganisationUnitsRow.OrganisationId 

     #Get the root provider path so that we can delete it later 
     $unitrow = $xml.OrganisationUnits.item('OrganisationUnitsRow') 

     #Get the AddressType from the XML file in text format 
     $n = $AddressRow.Item('AddressType')."#text" 

     #Get the AddressType from the XML file 
     $p = $AddressRow.Item('AddressType') 



     #if the source XML file AddressType (stored in $n) is found in the array of app results (stored in an array $var.code) then we have a match and the provider is OK. 
     if ($var.code -contains $n) 
     #if ($var.code -eq $n) 
     { 
      echo "MATCH. xml source value is $n which matches a value in the app. Provider ID $OrgID" 
     } 
     # The XML file AddressType (stored in $n) is NOT found in the array of the app results (web query stored in an array $var.code) then the entire provider must be DELETED from the XML file. 
     else 
     { 
      echo "NO MATCH. Source XML File value is $n. Provider ID $OrgID" 

      #This removes the entire provider (I think) 
      $unitrow.RemoveAll()  

      $xml.Save($XMLPath) 
      $xml.Save($xml) 
     } 

    } 

} 
else 
{ 
# No AddressType records were pulled back from the app, this could be an error. 
echo "No AddressType records found in the app, this could be an error" 

} 

} 

내 powershell 스크립트의 콘솔 출력은 다음과 같습니다.

HQ 
MAIN 
NOT_STATED 
OP 
AddressType records in application = 4 
NO MATCH. Source XML File value is TYPE1A. Provider ID ID1 ID2 ID3 
NO MATCH. Source XML File value is TYPE1B. Provider ID ID2 ID3 
NO MATCH. Source XML File value is TYPE2A. Provider ID ID2 ID3 
NO MATCH. Source XML File value is TYPE2B. Provider ID ID2 ID3 
NO MATCH. Source XML File value is TYPE3A. Provider ID ID2 ID3 

그래서 문제는 ID1가 제거 된 첫 번째 제공 1입니다. 2. 그것은 그대로 두었습니다. 스크립트를 수동으로 삭제하고 스크립트를 다시 실행하면 다음 공급자가 제거 된 다음 중지됩니다.

<?xml version="1.0" encoding="UTF-8"?> 
<OrganisationUnits> 
    <OrganisationUnitsRow> 
    </OrganisationUnitsRow> 
    <OrganisationUnitsRow num="2"> 
    <OrganisationId>ID2</OrganisationId> 
    <OrganisationName>PROVIDER_2</OrganisationName> 
    <Addresses> 
     <AddressesRow num="1"> 
     <AddressType>TYPE2A</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
     <AddressesRow num="2"> 
     <AddressType>TYPE2B</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
    </Addresses> 
    </OrganisationUnitsRow> 
    <OrganisationUnitsRow num="3"> 
    <OrganisationId>ID3</OrganisationId> 
    <OrganisationName>PROVIDER_3</OrganisationName> 
    <Addresses> 
     <AddressesRow num="3"> 
     <AddressType>TYPE3A</AddressType> 
     <AddressTypeDesc>Head Office</AddressTypeDesc> 
     </AddressesRow> 
    </Addresses> 
    </OrganisationUnitsRow> 
</OrganisationUnits> 

그것은 내가 $ unitrow.RemoveAll()를 사용하여 전체 제공자를 삭제하려면 제대로 OrganisationUnitsRow을 제거 아니에요 수 있습니다, 난 그냥 문이 안 열려는 순간을 참조하십시오.

답변

2

분명히 두 번째 아이가 더 이상 존재하지 않도록 첫 번째 아이를 확인하는 동안 부모 노드를 제거하려고합니다. 다른 문제도 있었지만 정확하고 간단한 예를 살펴 보는 것이 좋습니다. 바깥 쪽 루프에서는 제거 될 수있는 엔티티를 반복하고 안쪽 루프에서는 자식을 확인합니다. - 우리의 기준

  • %{$_.RemoveAll()}을 충족하는 모든 노드를 찾을 수 - 그들에게
  • 0을 제거

    if ($var.Count -gt 0) { 
        [string]$xpath = '/OrganisationUnits/OrganisationUnitsRow[not(./Addresses/AddressesRow/AddressType/text()[{0}])]' -f (($var | %{". = '{0}'" -f ($_ -replace "'","''")}) -join ' or ') 
        $xml.SelectNodes($xpath) | %{$_.RemoveAll()} 
    } 
    #output result to console to show what's been done 
    $xml | Format-Xml 
    

    설명

    • $xml.SelectNodes($xpath) : 여기
      $IsModified = $false 
      foreach ($UnitRow in $xml.OrganisationUnits.OrganisationUnitsRow) { 
          $OrgID = $UnitRow.OrganisationId 
          foreach ($AddressRow in $UnitRow.Addresses.AddressesRow) { 
           $n = $AddressRow.AddressType 
           if ($var.code -contains $n) { 
            echo "MATCH. blabla" 
           } else { 
            echo "NO MATCH. blabla" 
            $UnitRow.parentNode.RemoveChild($UnitRow) >$null 
            $IsModified = $true 
            break 
           } 
          } 
      } 
      
      if ($IsModified) { 
          $xml.Save($XMLPath) 
      } 
      
    +0

    작품 완벽하게, 많은 감사를 – zoomzoomvince

    0

    빠른 해결책이다

    위의 기준 (즉, $xpath 변수)는 원하는 주소 유형이 아닌 (또는 주소 유형이없는) 조직/제공 업체를 찾는 요구 사항을 구현하는 곳입니다.

    • '/OrganisationUnits/OrganisationUnitsRow

      - 반환되는 요소는 OrganisationUnitsRow
    • [입니다 - 우리는 다음에 해당하는 해당 행을 필터링
    • not(-
    • ./Addresses/AddressesRow/AddressType가없는 경우 행을 반환 -은 주소 유형이있는 주소 행
    • /text() - 텍스트 값이
    • [{0}] 인 우리가 통과 한 조건과 일치합니다.

    텍스트 경로에 넣은 조건은 "값이 $ var 목록에있는 위치입니다. 와 같은 작성 : VAR의 가치의 작은 따옴표 문제가 발생할 것입니다, 그래서 우리는 '''를 대체하여 그들을 탈출 : - $var | %{-". = '{0}'" - - $var 의 각 값에 대해 NB - ($_ -replace "'","''")-". = 'singleValueFromVar'" 을 성명을 만들 . - -join '또는'- join all the values together with or` 문

    $xpath 값 주어진다 :

    /OrganisationUnits/OrganisationUnitsRow[not(./Addresses/AddressesRow/AddressType/text()[. = 'HQ' or . = 'MAIN' or . = 'NOT_STATED' or . = 'OP'])]

    전체 샘플 코드

    $xml = [xml]@" 
    <OrganisationUnits> 
        <OrganisationUnitsRow> 
        </OrganisationUnitsRow> 
        <OrganisationUnitsRow num="2"> 
        <OrganisationId>ID2</OrganisationId> 
        <OrganisationName>PROVIDER_2</OrganisationName> 
        <Addresses> 
         <AddressesRow num="1"> 
         <AddressType>TYPE2A</AddressType> 
         <AddressTypeDesc>Head Office</AddressTypeDesc> 
         </AddressesRow> 
         <AddressesRow num="2"> 
         <AddressType>TYPE2B</AddressType> 
         <AddressTypeDesc>Head Office</AddressTypeDesc> 
         </AddressesRow> 
        </Addresses> 
        </OrganisationUnitsRow> 
        <OrganisationUnitsRow num="3"> 
        <OrganisationId>ID3</OrganisationId> 
        <OrganisationName>PROVIDER_3</OrganisationName> 
        <Addresses> 
         <AddressesRow num="3"> 
         <AddressType>HQ</AddressType> 
         <AddressTypeDesc>Head Office</AddressTypeDesc> 
         </AddressesRow> 
        </Addresses> 
        </OrganisationUnitsRow> 
    </OrganisationUnits> 
    "@ 
    
    clear-host 
    [string[]]$var = @('HQ','MAIN','NOT_STATED','OP') 
    if ($var.Count -gt 0) { 
        [string]$xpath = '/OrganisationUnits/OrganisationUnitsRow[not(./Addresses/AddressesRow/AddressType/text()[{0}])]' -f (($var | %{". = '{0}'" -f ($_ -replace "'","''")}) -join ' or ') 
        $xml.SelectNodes($xpath) | %{$_.RemoveAll()} 
    } 
    #output result to console to show what's been done 
    $xml | Format-Xml