2013-06-28 91 views
0

我有一些XML数据具有很多属性和多个具有相同名称的元素,我想将它们压缩为CSV文件。数据XML看起来是这样的:PowerShell中的XML父项和子项属性和元素

<?xml version="1.0" encoding="utf-8"?> 
<SEGMENTS> 
    <SEGMENT NAME="webcluster"> 
     <RESULTPAGE> 
      <RESULTSET FIRSTHIT="1" LASTHIT="100" HITS="100" TOTALHITS="100"> 
       <HIT NO="1" RANK="19000" SITEID="0" MOREHITS="100"> 
        <FIELD NAME="rank">19000</FIELD> 
        <FIELD NAME="id">1</FIELD> 
        <FIELD NAME="url">C:\website.com\folder1\file1.txt</FIELD> 
        <FIELD NAME="filename">file1.txt</FIELD> 
        <FIELD NAME="path">https://website.com/folder1/</FIELD> 
       </HIT> 
       <HIT NO="2" RANK="19000" SITEID="0" MOREHITS="100"> 
        <FIELD NAME="rank">19000</FIELD> 
        <FIELD NAME="id">2</FIELD> 
        <FIELD NAME="url">C:\website.com\folder1\file2.txt</FIELD> 
        <FIELD NAME="filename">file2.txt</FIELD> 
        <FIELD NAME="path">https://website.com/folder1/</FIELD> 
       </HIT> 
       <HIT NO="3" RANK="18999" SITEID="0" MOREHITS="100"> 
        <FIELD NAME="rank">18999</FIELD> 
        <FIELD NAME="id">3</FIELD> 
        <FIELD NAME="url">C:\website.com\folder5\file3.txt</FIELD> 
        <FIELD NAME="filename">file3.txt</FIELD> 
        <FIELD NAME="path">C:\website.com\folder\</FIELD> 
       </HIT> 
      </RESULTSET> 
     </RESULTPAGE> 
    </SEGMENT> 
</SEGMENTS> 

而且我想遍历它来产生这样的

​​

我的代码是:

[xml]$xml=Get-Content .\xmlfile.xml 
$hits = $xml.segments.segment.resultpage.resultset.hit 
foreach($hit in $hits) 
{ 
    foreach($field in $hit.field) 
    { 
     if (field."NAME" -eq 'url') 
     { 
      write-output $hit.no $field."#VALUE" 
     } 
    } 
} 

我不断收到错误。我可以通过序号位置($ hits [0] .field [4])引用它们来访问不同的元素和属性,但是我希望在FIELD值可能不同的顺序时防止将来的输出。

任何人都可以建议我如何做到这一点?我尝试使用select-XML,发现更麻烦,但也许这是更优雅的方法。

回答

1

像这样的事情似乎这样做,虽然我不喜欢那样。

[xml]$xml=Get-Content .\xmlfile.xml 
$hits = $xml.segments.segment.resultpage.resultset.hit 
foreach($hit in $hits) 
{ 
    $result = new-object PSObject -Property @{ hit = $hit.no; filename = ""; path = ""} 

    foreach($field in $hit.field) 
    { 
     if ($field."NAME" -eq 'url') 
     { 
      $result.path = $field."#text" 
     } 
     if ($field."NAME" -eq 'filename') 
     { 
      $result.filename = $field."#text" 
     } 
    } 
    write-output $result 
} 

,或者只是抢占了所有字段,然后选择相关:

[xml]$xml=Get-Content .\xmlfile.xml 
$hits = $xml.segments.segment.resultpage.resultset.hit 
foreach($hit in $hits) 
{ 
    $result = new-object PSObject -Property @{ hit = $hit.no } 
    $hit.field | % { Add-Member -InputObject $result -MemberType NoteProperty -Name $_."NAME" -Value $_."#text"} 
    $result | select hit,url,filename | write-output 
} 
+0

这工作!谢谢! 有人建议离线: '[XML] $ hitfile =获取内容fastxml.xml '的foreach($创下$ hitfile.segments.segment.resultpage.resultset.hit) '{ '$行= $ mjatable .NewRow() '$ row.Hit = $ hit.No '$ row.InternalID = $ hit.field | ?{$ _。name -eq'Internalid'} | foreach {$ _。'#text'} '$ row.URL = $ hit.field | ?{$ _。name -eq'url'} | foreach {$ _。'#text'} '$ mjaTable.Rows.Add($ row) '} '$ mjaTable | format-table -AutoSize – MJA

+0

我仍然很好奇,如果可以使用NAME attrib =(“url”或“Internalid”)来引用一个FIELD元素而不使用WHERE-OBJECT过滤器来检索'#text'值,但是如果不是,这两个解决方案完成了工作 再次感谢! – MJA

+0

评论中的代码是PITA,更新了答案 – user1578107

0

尝试是这样的:

Select-Xml -Xml $xml -XPath '//HIT' | Foreach { 
    $num=$_.Node.NO 
    $filenameAttr = $_.Node.Field | where {$_.Name -eq 'filename'} 
    $pathAttr = $_.Node.Field | where {$_.Name -eq 'path'} 
    new-object psobject -Property ([ordered]@{HIT=$num; filename = $filenameAttr.InnerText; path = $pathAttr.InnerText}) 
} 
+0

Keith,尝试上面的代码我得到: 无法找到类型[ordered]:确保包含此类型已加载 在行:6 char:45 + new-object psobject -Property([ordered] <<<< {{HIT = $ num; filename = $ filenameAttr.InnerText; path = $ pathAttr.InnerText}) + CategoryInfo:InvalidOperation:(ordered:String)[],RuntimeException + FullyQualifiedErrorId:TypeNotFound 我会尝试一些修改 – MJA

+0

啊,这是PowerShell V3的新功能。您可以删除它,但创建的对象中的属性顺序将是随机的。 –

0

相结合的方法。选择允许以特定顺序获取字段。

[xml]$xml=Get-Content .\xmlfile.xml 
$hits = $xml.segments.segment.resultpage.resultset.hit 
foreach($hit in $hits) 
{ 
    $r = @{hit = $hit.no; url = "N/A";filename="N/A"} 
    $hit.field | % { $r[$_."NAME"] = $_."#text" } 
    New-Object PSObject -Property $r | Select hit,url,filename 
}