#xml #powershell #xpath
Вопрос:
У меня есть приведенный ниже XML (это часть более крупного документа):
lt;class type="I want to filter on whatever value this is"gt; lt;instance name="QuestionSet4"gt; lt;property name="QuestionSetName"gt;QuestionSet4lt;/propertygt; lt;property name="Ratio"gt;5lt;/propertygt; lt;/instancegt; lt;instance name="QuestionSetTrust"gt; lt;property name="QuestionSetName"gt;QuestionSetTrustlt;/propertygt; lt;property name="Ratio"gt;5lt;/propertygt; lt;/instancegt; lt;/classgt;
Моя цель состоит в том , чтобы использовать PowerShell Select-Xml
таким образом, чтобы я мог возвращать оба name
свойства для каждого узла, используя XPath, который фильтрует класс type
, чтобы вывод был примерно таким:
QuestionSetName, Ratio QuestionSet4, 5 QuestionSetTrust, 5
Класс type
уникален в документе, поэтому я задался вопросом, можно ли фильтровать на основе этого, а не жестко кодировать элемент, как показано ниже:
/root/class[3]/@type
Вместо этого это было бы /root/class/@type="I want to filter on whatever value this is"...
Имена экземпляров будут меняться от документа к документу, поэтому я также не могу фильтровать это.
Ответ №1:
Вы можете разрешить соответствующие instance
узлы с помощью выражения XPath, например, следующего:
//class[@type = 'I want to filter on whatever value this is']/instance
Таким образом, вы могли бы построить желаемые выходные объекты следующим образом:
$xml |Select-Xml -XPath "//class[@type = 'I want to filter on whatever value this is']/instance" |ForEach-Object { [pscustomobject]@{ QuestionSetName = ($_.Node |Select-Xml "./property[@name='QuestionSetName']").Node.InnerText Ratio = ($_.Node |Select-Xml "./property[@name='Ratio']").Node.InnerText } }
Если у вас есть много lt;property /gt;
элементов, которые нужно перечислить для каждого lt;instance /gt;
, это быстро приведет к беспорядку, но вы можете немного упростить это следующим образом:
$propertyNames = 'QuestionSetName','Ratio','Size','SomeOtherProperty' $xml |Select-Xml -XPath "//class[@type = 'I want to filter on whatever value this is']/instance" |ForEach-Object { $properties = [ordered]@{} foreach($name in $propertyNames){ $properties[$name] = ($_.Node |Select-Xml "./property[@name='${name}']").Node.InnerText } [pscustomobject]$properties }
Комментарии:
1. Ваш первый отрывок работает идеально. Спасибо!