2016-07-20 3 views
1

Если у меня есть файл с XML как:Синтаксический XML в Powershell

<?xml version="1.0" encoding="utf-8"?> 
<package date-created="19/07/2016" version="6" system="6"> 
    <description /> 
    <system /> 
    <res id="1057002654" name="ABC" path="/DEF" type="F" mimeType="application/x-shared"> 
    <description /> 
    <keywords /> 
    <resver id="1057014163" major="1" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057014677" major="2" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057015106" major="3" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057016183" major="4" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057016374" major="5" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017622" major="6" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017704" major="7" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    <resver id="1057017863" major="8" minor="0" revision="0" effective-from="20010101000000" effective-to="20991231235959" /> 
    </res> 
</package> 

Там может быть сотни предметов, и в них может быть один или несколько. В Powershell я пытаюсь найти последние resver id значение, где res id equalls .

Я начал с этим:

$path = 'C:\TEST\package.xml' 
$myxml = [xml](Get-Content $path) 
$node = $myxml.package.res.resver | where {$_.id -eq "1057002654"} 
$node.id = '123' 
$myxml.Save($path) 

Это был просто быстрый тест, чтобы увидеть, если я мог бы получить биту я хотел и обновить его, но терпит неудачу с:

Property 'id' cannot be found on this object; make sure it exists and is settable. 

Затем я попробовал что-то вроде:

$xml = [xml](Get-Content 'C:\TEST\package.xml') 
$nodes = $xml.SelectNodes("//*[@res]") 
foreach ($node in $nodes) { 

$node.Attributes | %{$_} > C:\TEST\disk.txt } 

Это фактически записывает все значения в атрибутах в .txt-файл, но не может видеть m, чтобы найти способ сделать то, что я хочу.

/Edit - Исправлено тем, что я на самом деле хотел сделать. Законченный с кодом, как это, где $ Ref является элемент в массиве Ссылки

foreach ($Ref in $References) 
{ 
    $xml = [xml](Get-Content 'C:\TEST\package.xml') 
    $res = $xml.SelectSingleNode('//res[@id = $Ref]/child::resver') 
    $resource = $res.id + ".txt" 

    # more stuff here 
} 

$ Получение этой ошибки, хотя:

Exception calling "SelectSingleNode" with "1" argument(s): "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function." 
At C:\TEST\script.ps1:22 char:38 
+ [string] $res = $xml.SelectSingleNode <<<< ('//res[@id = $Ref]/child::resver') 
    + CategoryInfo   : NotSpecified: (:) [], MethodInvocationException 
    + FullyQualifiedErrorId : DotNetMethodException 
+5

Вы должны [не использовать регулярное выражение] (http://stackoverflow.com/a/1732454/52598) для разбора XML, но XPath или XQuery. fwiw - я могу порекомендовать RegexBuddy, чтобы лучше понять regex * (не связанный, но заядлый пользователь) *. Составление xquery оставлено как упражнение * (читайте как: не моя чашка чая, извините) * –

+2

Это недопустимо XML, само имя узла не может иметь значение атрибута (а '=' не разрешено как часть имени) –

+0

@LievenKeersmaekers - извинения за действительно мусорный вопрос. Я полностью отредактировал его, поэтому было бы очень полезно, если бы вы могли взглянуть, пожалуйста. – hshah

ответ

3

Используйте parent:: оси найти подходящий родитель узла после определения местонахождения узла <resver /> с правильным ID:

$path = 'C:\TEST\package.xml' 
$myxml = [xml](Get-Content $path) 
# Locate resver, select parent res node 
$res = $myxml.SelectSingleNode('//resver[@id = "1057014163"]/parent::res') 
# Update id 
$res.SetAttribute('id','123') 
# Save document 
$myxml.Save($path) 

Вы также можете использовать .. псевдоним для родительского узла:

//resver[@id = "1057014163"]/.. 

Или as PetSerAl notes выберите res узел, который имеет описанный дочерний узел:

//res[resver/@id = "1057014163"] 

Для делать это по-другому (найти все resver дочерний узел id значения на основе исходных узлов id):

$ids = $myxml.SelectNodes('//res[@id = "1057002654"]/resver[@id]') |Select -Expand id 

(уведомление использование SelectNodes() вместо SelectSingleNode())

+0

Благодаря вам и @PetSerAl. На протяжении веков меня везли! :) – hshah

+0

Извините, ребята, добавили немного больше к моему вопросу, поскольку я понял, что я идиот и смотрю на это наоборот. У меня есть идентификаторы и требуется последний идентификатор resver. Получил код, но он дает мне ошибки :( – hshah

+0

@hshah см. Обновление –

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