2012-06-17 4 views
3

Учитывая следующий пример сценария (сохранить как sample.txt на моем жестком диске):Как получить список дочерних узлов из XML

DECLARE @xVar XML 
SET @xVar = 
    '<bookstore> 
     <book> 
     <title>Writing Secure Code</title> 
     <author> 
      <first-name>Michael</first-name> 
      <last-name>Howard</last-name> 
     </author> 
     <author> 
      <first-name>David</first-name> 
      <last-name>LeBlanc</last-name> 
     </author> 
     <price>39.99</price> 
     </book> 
     <book> 
     <title>Old Man and the sea</title> 
     <author> 
      <first-name>Earnest</first-name> 
      <last-name>Hemmingway</last-name> 
     </author> 
     <price> 9.99</price> 
     </book> 
    </bookstore> 
    ' 

SELECT nref.value('first-name[1]', 'nvarchar(50)') FirstName, 
     nref.value('last-name[1]', 'nvarchar(50)') LastName 
FROM @xVar.nodes('//author') AS R(nref) 
WHERE nref.exist('.[first-name != "David"]') = 1 

Я хочу, чтобы извлечь XML и если определить дочерние узлы добавлены к узлу книга. Для этого варианта использования предположим, что автором является новый узел.

Я написал сценарий, который работает, но это, кажется, крайне неэффективно:

Set-StrictMode -Version Latest 

cls 
#The list of fields that I want to find 
[array]$expected_fields = "title", "price" 

#extract the xml from sample.txt and put it in an xml variable 
[string]$file_script = Get-Content "C:\PowerShellScripts\sample.txt" 
[int]$start_pos = $file_script.IndexOf("'") + 1 
[int]$end_pos = $file_script.SubString($start_pos + 1).IndexOf("'") + 1 
[xml]$xml_result = $file_script.SubString($start_pos,$end_pos) 

#NOTE: THIS IS THE PART THAT FEELS WRONG 
#Convert the xml snipput into CSV file and then get the headers (which is the only thing I want) 
$export_file_name = "C:\PowerShellScripts\test.csv" 
Select-Xml 'child::bookstore/book' $xml_result | Select-Object -expand Node | Export-Csv $export_file_name -NoTypeInformation -Delimiter:"`t" -Encoding:UTF8 
[string]$field_names = Get-Content $export_file_name | Select-Object -first 1 
Remove-Item "C:\Users\Jennifer\Google Drive\PowerShellScripts\test.csv" 
[array]$found_fields = $field_names.Replace("""","").Split("`t") 

#report new fields 
foreach ($specific_field in $found_fields) { 
    if ($expected_fields -notcontains $specific_field) 
    { 
     Write-Host "New field found:" $specific_field 
    } 
} 

Есть ли лучший способ для заполнения * $ found_fields * вместо создания файла CSV, сохраняя первую строку в переменной а затем удалите файл CSV?

ответ

3

Попробуйте изменить -Expand от узла к ИмяWhere-Object исключить название и цена)

$xml_result.SelectNodes("bookstore/book/*") | Select-Object -Expand Name | Where-Object { ($_ -ne "title") -and ($_ -ne "price") } 

Это даст вам какие-либо неожиданные дочерние узлы book.

+0

Отлично! Не только ответил на мой вопрос, но помог мне увидеть слабость в моем оригинальном скрипте: «новые» дочерние узлы книги добавлены после того, как исходный узел не появился. Эта строка кода исправляет это. Ty! – ray

Смежные вопросы