2017-08-14 35 views
1

PowerShellのXMLの理解に少し助けが必要です。 私はこのようないくつかのXMLファイルを持っている:PowerShellで名前空間を使用してXMLを解析する

<?xml version="1.0" encoding="UTF-8"?> 
<catalog xmlns="http://www.example.com/xml/catalog/2006-10-31"> 
    <product product-id="11210"> 
     ... 
     <available-flag>true</available-flag> 
     <online-flag>false</online-flag> 
     <online-flag site-id="ru">true</online-flag> 
     <online-flag site-id="fr">true</online-flag> 
     <online-flag site-id="uk">false</online-flag> 
     <online-flag site-id="de">true</online-flag> 
     ... 
    </product> 
    <product product-id="50610"> 
     ... 
     <available-flag>true</available-flag> 
     <online-flag>true</online-flag> 
     <online-flag site-id="ru">false</online-flag> 
     <online-flag site-id="fr">true</online-flag> 
     <online-flag site-id="uk">false</online-flag> 
     <online-flag site-id="de">fasle</online-flag> 
     ... 
    </product> 
    <product product-id="82929"> 
     ... 
     <available-flag>true</available-flag> 
     <online-flag>true</online-flag> 
     <online-flag site-id="ru">false</online-flag> 
     <online-flag site-id="fr">true</online-flag> 
     <online-flag site-id="uk">false</online-flag> 
     <online-flag site-id="de">true</online-flag> 
     ... 
    </product> 
</catalog> 

私はPowerShellで二つの要素の値を取得する必要があります。

  • <online-flag>site-id属性を持たない)
  • <online-flag site-id="ru">

製品の場合はproduct-id="50610"です。

私は、次のコードを持っている:私は必要な製品のノードを選択することができています。このコードで

  1. $Path = "C:\Temp\0\2017-08-12_190211.xml" 
    $XPath = "/ns:catalog/ns:product[@product-id='50610']" 
    
    $files = Get-ChildItem $Path | Where {-not $_.PSIsContainer} 
    
    if ($files -eq $null) { 
        return 
    } 
    
    foreach ($file in $files) { 
        [xml]$xml = Get-Content $file 
        $namespace = $xml.DocumentElement.NamespaceURI 
        $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) 
        $ns.AddNamespace("ns", $namespace) 
        $product = $xml.SelectSingleNode($XPath, $ns) 
    } 
    

    いくつかの質問を。 PowerShellは示しています

    online-flag  : {true, online-flag, online-flag, online-flag...} 
    

    しかし、どのように、私は必要なonline-flag要素(それが可能であれば両方の方法:のXPath 1とオブジェクト1)の値を選択することができますか?

  2. 「オブジェクト」の方法でノードを選択することはできますか?私はいくつかのファイル、ファイル名を選択するための最良の方法は何か、グローバルなオンライン・フラグ(属性なし)、特定のオンライン・フラグを持っている場合は

    $product = $xml.catalog.product | 
          Where-Object {$_."product-id".value -eq "50610"} 
    
  3. :このような?

答えて

1

使用二つの異なるXPath式:

  1. 特定の属性なしでノードを選択する:特定の属性値を持つノードを選択するため

    //ns:product[@product-id='50610']/ns:online-flag[not(@site-id)] 
    
  2. //ns:product[@product-id='50610']/ns:online-flag[@site-id='ru'] 
    

あなたは、現在のノード(.)にXPath式を相対することによって、既に選択されたノードに対するノードを選択することができます:あなたは、ファイル名からなるデータと2つのノード値を引き起こす必要がある場合は、私がお勧めしたい

$XPath = "/ns:catalog/ns:product[@product-id='50610']" 
... 
$product = $xml.SelectSingleNode($XPath, $ns) 
$product.SelectSingleNode("./ns:online-flag[not(@site-id)]", $ns) 
$product.SelectSingleNode("./ns:online-flag[@site-id='ru']", $ns) 

建物のカスタムオブジェクト:ドット表記とフィルタリングを使用して

$files | ForEach-Object { 
    [xml]$xml = Get-Content $_ 
    ... 
    New-Object -Type PSObject -Property @{ 
     'Filename' = $_ 
     'online' = $product.SelectSingleNode("./ns:online-flag[not(@site-id)]", $ns).'#text' 
     'ru_online' = $product.SelectSingleNode("./ns:online-flag[@site-id='ru']", $ns).'#text' 
    } 
} 

Where-Object経由では可能なはずですが、私はそれをお勧めしません。 XPathははるかに効率的です。

+0

こんにちはアンスガー!ご回答有難うございます。私は既にドット表記法が機能していると言いました。それは便利ではないと私は同意します。あなたの例の問題は、私のXMLファイルが非常に大きく、2つのノードを選択するのに時間がかかるということです。私の例のように最初に製品を選択してから、XPathを使ってオンラインフラグ要素の値を選択することは可能ですか?この場合、XPathはどのようになりますか? – Alterant

+0

$ product.SelectSingleNode( "/ ns:product/ns:online-flag [@ site-id = 'ru']"、$ ns)、 $ product.SelectSingleNode( " /製品名/オンラインフラグ[@ site-id = 'ru']」)、 $ /SSS/NOS:オンラインフラグ[@ site-id = 'ru']」、 $ product.SelectSingleNode product.SelectSingleNode( "/ online-flag [@ site-id = 'ru']")。 この$製品。GetElementsByTagName( "online-flag")は動作します。しかし結果は単なる値ではなく、値のリストです。 – Alterant

+0

ここで答えが見つかりました:https://stackoverflow.com/questions/2238201/xmlnode-selectsinglenode-returns-element-outside-current – Alterant

0

私は、「オブジェクト」の方法で、私は必要なデータを取得することができた:

$product = $xml.catalog.product | Where-Object {$_."product-id" -eq "50610"} 
$of = $product."online-flag" 
$glblsid = $of | Where-Object {$_ -is [System.String]} 
$specsid = ($of | Where-Object {$_."site-id" -eq "ru"})."#text" 

しかし、私はこれを行うために管理方法が好きではありません。より便利なソリューションはありますか?

2番目の質問への答えははいです - 最初の行を参照してください。

1

このトピックを完了するには私は、ドットスタイル、ファイル上のXPath、ノード上のXPathの3つのメソッドのパフォーマンスを測定しました。それらの間には大きな違いはありません。 詳細はこちらです。

私は2回、それぞれ60MBの2つのファイルを解析しました。

  1. オブジェクトスタイル(ドットスタイル)

    ... 
    $StartTime = Get-Date 
    foreach ($file in $files) { 
        [xml]$xml = Get-Content $file 
    
        #Object style 
        $product = $xml.catalog.product | Where-Object {$_."product-id" -eq "50610"} 
        $of = $product."online-flag" 
        $glblsid = $of | Where-Object {$_ -is [System.String]} 
        $specsid = ($of | Where-Object {$_."site-id" -eq "ru"})."#text" 
        Write-Output "$($file.Name) $glblsid $specsid" 
    } 
    $EndTime = Get-Date 
    $TimeSpan = New-TimeSpan -Start $StartTime -End $EndTime 
    Write-Output $TimeSpan.TotalMilliseconds 
    

    結果:

    ... 
    $StartTime = Get-Date 
    foreach ($file in $files) { 
        [xml]$xml = Get-Content $file 
    
        #XPath on the file 
        $namespace = $xml.DocumentElement.NamespaceURI 
        $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) 
        $ns.AddNamespace("ns", $namespace) 
        $glblsid = $xml.SelectSingleNode("/ns:catalog/ns:product[@product-id='50610']/ns:online-flag[not(@site-id)]", $ns).'#text' 
        $specsid = $xml.SelectSingleNode("/ns:catalog/ns:product[@product-id='50610']/ns:online-flag[@site-id='ru']", $ns).'#text' 
        Write-Output "$($file.Name) $glblsid $specsid" 
    } 
    $EndTime = Get-Date 
    $TimeSpan = New-TimeSpan -Start $StartTime -End $EndTime 
    Write-Output $TimeSpan.TotalMilliseconds 
    

    結果::

     
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    36269,535 
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    36628,3304 
    
  2. XPathのファイルに

     
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    36129,1368 
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    38890,3014 
    
  3. ノード上のXPath:

    ... 
    $StartTime = Get-Date 
    foreach ($file in $files) { 
        [xml]$xml = Get-Content $file 
    
        #XPath on the node 
        $namespace = $xml.DocumentElement.NamespaceURI 
        $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) 
        $ns.AddNamespace("ns", $namespace) 
        $product = $xml.SelectSingleNode("/ns:catalog/ns:product[@product-id='50610']", $ns) 
        $glblsid = $product.SelectSingleNode("ns:online-flag[not(@site-id)]", $ns).'#text' 
        $specsid = $product.SelectSingleNode("ns:online-flag[@site-id='ru']", $ns).'#text' 
        Write-Output "$($file.Name) $glblsid $specsid" 
    } 
    $EndTime = Get-Date 
    $TimeSpan = New-TimeSpan -Start $StartTime -End $EndTime 
    Write-Output $TimeSpan.TotalMilliseconds 
    

    結果:

     
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    33477,1708 
    PS> .\ParseXML2.ps1 
    2017-08-10_190159.xml false false 
    2017-08-11_190203.xml false true 
    34116,7626 
    
関連する問題