2011-09-13 36 views
3

我從XML文件收集信息並對其進行處理。我的查詢是自由的,以確保我得到我想要的所有可能的元素。因此,結果列表中可能會出現重複元素(稱爲$components)。我通過Sort-Object運行結果,然後運行Get-Unique來查找所有唯一對象。根據我的理解,每個獨特對象中的一個應該由Get-Unique保留。但它消除了一些已經唯一的對象(在原始列表中沒有重複的對象)。Powershell,獲取唯一性吹走已經唯一的單個對象

這裏是一個簡化的例子。只需粘貼到這個PowerShell中或保存到PS1文件並運行(如下圖所示輸出):

$xmlDoc = [xml]@' 
<root> 
    <component Id='component1'> 
     <regkey Id='regkey1'/> 
    </component> 
    <component Id='component2'> 
     <file Id='file1' /> 
    </component> 
</root> 
'@ 

$files = $xmlDoc.SelectNodes("//file[@Id='file1']") 
$regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']") 
$components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2']") 
$components += $regkeys | Select-Object -ExpandProperty 'ParentNode' 
$components | Sort-Object -Property 'Id' 
Write-Host 
$components | Sort-Object -Property 'Id' | Get-Unique 

如果粘貼到PowerShell的,打的最後一行後進入。

輸出是這樣的:

PS C:\> $xmlDoc = [xml]@' 
>> <root> 
>>  <component Id='component1'> 
>>   <regkey Id='regkey1'/> 
>>  </component> 
>>  <component Id='component2'> 
>>   <file Id='file1' /> 
>>  </component> 
>> </root> 
>> '@ 
>> 
PS C:\> $files = $xmlDoc.SelectNodes("//file[@Id='file1']") 
PS C:\> $regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']") 
PS C:\> $components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2 
']") 
PS C:\> $components += $regkeys | Select-Object -ExpandProperty 'ParentNode' 
PS C:\> $components | Sort-Object -Property 'Id' 

Id             regkey 
--             ------ 
component1           regkey 
component1           regkey 
component2 


PS C:\> Write-Host 

PS C:\> $components | Sort-Object -Property 'Id' | Get-Unique 

Id             regkey 
--             ------ 
component1           regkey 


PS C:\> 

注意如何component2完全消失,一旦我們管Get-Unique。任何人都可以解釋這一點,並提供一個解決方案,保持查詢方案大致相同?

編輯:我認爲它會使用-eq運算符來查看元素是否是對內存中同一對象的引用。如果我手動嘗試-eq它顯示正確的對象是相等的。但Get-Unique似乎在做別的事情。如果您將此代碼添加到上面的腳本結束它顯示了對象equivelance:

Write-Host 
Write-Host "0: $($components[0].Id)" 
Write-Host "1: $($components[1].Id)" 
Write-Host "2: $($components[2].Id)" 
Write-Host ("0 vs 1: " + ($components[0] -eq $components[1])) 
Write-Host ("0 vs 2: " + ($components[0] -eq $components[2])) 
Write-Host ("1 vs 2: " + ($components[1] -eq $components[2])) 

輸出(從腳本文件運行時):

0: component1 
1: component2 
2: component1 
0 vs 1: False 
0 vs 2: True 
1 vs 2: False 
+2

嘗試'-asstring'參數。從Get-Unique的Technet文章 - **如果沒有此參數,數據將被視爲一個對象,因此,當您將相同類型的對象集合提交給Get-Unique(如文件集合)時,它將返回一個(第一次)** – JNK

+0

我試過了,沒有運氣。 :/ – Vimes

+0

我認爲重複的對象實際上是對內存中同一對象的兩個引用,並且預期比較在默認情況下是正確的。顯然還有更多事情要做。 – Vimes

回答

2

我的直覺是,Get-Unique效果很好對於整型,字符串等標量類型(也可以是一組衆所周知的類型),而不是一般對象,因爲沒有通用的規則來決定對象是否相等。

考慮這個例子:

# getting unique string, works well 
get-process | sort-object | select -expand processname | get-unique 

# getting unique objects (PSObject), wrong result 
get-process | sort-object | select -property processname | get-unique 

# getting unique objects by their string representation, works well 
get-process | sort-object | select -property processname | get-unique -asString 

# what is the string representation? 
[string](get-process | sort-object | select -property processname)[0] 
#returns @{ProcessName=audiodg} 

在你的情況字符串表示:

[string]($components | Sort-Object -Property 'Id')[0] 
# System.Xml.XmlElement 

這就是爲什麼即使-asString參數不起作用

5

您可以使用sort-object-unique標誌。這給我預期的結果:

$components | Sort-Object -Property 'Id' -Unique 
+0

這看起來對上面的例子有用,但是當我嘗試使用我的實際代碼時,我遇到了相反的問題:兩個副本都消失了,剩下的只有原始列表中唯一的一個對象。我很難過。不幸的是,我無法發佈我的實際數據(這是爲了工作)。我不認爲我有時間弄清楚我的實際數據與上面的例子有什麼不同。 – Vimes

+0

糟糕,在我上面的評論中,我沒有相反的問題。我有完全相同的問題。 :P混淆了我的對象。 – Vimes