Xml 根据子元素的值查找主元素,然后更改不同子元素的值

Xml 根据子元素的值查找主元素,然后更改不同子元素的值,xml,powershell,Xml,Powershell,我有一个具有以下结构的xml文件: <PARENT> <LIBRARY> <BOOKS> <BOOK> <BOOK_DATA> <BOOK_TITLE>HOBBIT</BOOK_TITLE> </BOOK_DATA> &

我有一个具有以下结构的xml文件:

<PARENT>
    <LIBRARY>
        <BOOKS>
            <BOOK>
                <BOOK_DATA>
                    <BOOK_TITLE>HOBBIT</BOOK_TITLE>
                </BOOK_DATA>
                <STATUS>NotRead</STATUS>
            </BOOK>
            <BOOK>
                <BOOK_DATA>
                    <BOOK_TITLE>LOTR_FOTR</BOOK_TITLE>
                </BOOK_DATA>
                <STATUS>NotRead</STATUS>
            </BOOK>
            <BOOK>
                <BOOK_DATA>
                    <BOOK_TITLE>LOTR_TT</BOOK_TITLE>
                </BOOK_DATA>
                <STATUS>NotRead</STATUS>
            </BOOK>
            <BOOK>
                <BOOK_DATA>
                    <BOOK_TITLE>LOTR_ROTK</BOOK_TITLE>
                </BOOK_DATA>
                <STATUS>NotRead</STATUS>
            </BOOK>
        </BOOKS>
    </LIBRARY>
</PARENT>

我建议按标记名查找元素。然后,您需要在层次结构的更高层次上访问书籍的相应状态

然后很容易设置状态

$foundedElement = $test.GetElementsByTagName("BOOK_TITLE") |Where-Object {$_."#text" -eq $BookTitle}

$foundedElement.ParentNode.ParentNode.STATUS = $NewStatus

$test.Save($fileName)

我建议按标记名查找元素。然后,您需要在层次结构的更高层次上访问书籍的相应状态

然后很容易设置状态

$foundedElement = $test.GetElementsByTagName("BOOK_TITLE") |Where-Object {$_."#text" -eq $BookTitle}

$foundedElement.ParentNode.ParentNode.STATUS = $NewStatus

$test.Save($fileName)

我建议对此问题使用
XPath

[xml]$xml = ' ... '

$bookTitle = 'LOTR_TT'
$newStatus = 'Read'
$node = $xml.SelectSingleNode("//BOOK[BOOK_DATA/BOOK_TITLE='$bookTitle']/STATUS")
$node.'#text' = $newStatus
这里的重要部分是过滤器:

//BOOK[BOOK_DATA/BOOK_TITLE='$bookTitle']/STATUS
这将从与筛选器
book\u TITLE='$bookTitle'
匹配的书籍中选择
STATUS
节点,powershell将
InnerText
作为
\text
属性公开


在示例脚本中使用:

param(
    [string]
    $BookTitle = 'LOTR_TT',

    [string]
    $NewStatus = 'Read',

    [string]
    $FilePath = 'C:\file.xml'
)

[xml]$xml = Get-Content -Path $FilePath

$node = $xml.SelectSingleNode("//BOOK[BOOK_DATA/BOOK_TITLE='$BookTitle']/STATUS")
$node.'#text' = $NewStatus

$xml.Save($FilePath)

或者,如果要查找包含要更改为读取的字符串的所有节点,可以执行以下操作:

$xml.SelectNodes("//BOOK[BOOK_DATA/BOOK_TITLE[contains(., '$BookTitle')]]/STATUS") |
    ForEach-Object { $_.'#text' = $NewStatus }

我建议对此问题使用
XPath

[xml]$xml = ' ... '

$bookTitle = 'LOTR_TT'
$newStatus = 'Read'
$node = $xml.SelectSingleNode("//BOOK[BOOK_DATA/BOOK_TITLE='$bookTitle']/STATUS")
$node.'#text' = $newStatus
这里的重要部分是过滤器:

//BOOK[BOOK_DATA/BOOK_TITLE='$bookTitle']/STATUS
这将从与筛选器
book\u TITLE='$bookTitle'
匹配的书籍中选择
STATUS
节点,powershell将
InnerText
作为
\text
属性公开


在示例脚本中使用:

param(
    [string]
    $BookTitle = 'LOTR_TT',

    [string]
    $NewStatus = 'Read',

    [string]
    $FilePath = 'C:\file.xml'
)

[xml]$xml = Get-Content -Path $FilePath

$node = $xml.SelectSingleNode("//BOOK[BOOK_DATA/BOOK_TITLE='$BookTitle']/STATUS")
$node.'#text' = $NewStatus

$xml.Save($FilePath)

或者,如果要查找包含要更改为读取的字符串的所有节点,可以执行以下操作:

$xml.SelectNodes("//BOOK[BOOK_DATA/BOOK_TITLE[contains(., '$BookTitle')]]/STATUS") |
    ForEach-Object { $_.'#text' = $NewStatus }

据我所知,您的代码中有两个错误:

  • 您应该引用
    $booktile
    $NewStatus
    的值,使它们成为
    $BookTitle='LOTR\u TT'
    $NewStatus='Read'
  • 您只引用了以下内容:
    $。STATUS='$NewStatus'
    ,通过这样做,您可以将STATUS设置为“$NewStatus”的literal值。删除这些引号以插入变量的

    $\状态=$NewStatus


  • 在那之后,if对我来说很好。

    据我所知,您的代码中有两个错误:

  • 您应该引用
    $booktile
    $NewStatus
    的值,使它们成为
    $BookTitle='LOTR\u TT'
    $NewStatus='Read'
  • 您只引用了以下内容:
    $。STATUS='$NewStatus'
    ,通过这样做,您可以将STATUS设置为“$NewStatus”的literal值。删除这些引号以插入变量的

    $\状态=$NewStatus


  • 之后,if对我很有效。

    当引用
    $BookTitle
    $NewStatus
    的值时,它对我有效。。如果未加引号,则会产生错误:
    术语“LOTR\u TT”无法识别为cmdlet、函数、脚本文件或可操作程序的名称。
    。这是您意外的结果吗?当引用
    $BookTitle
    $NewStatus
    的值时,它对我有效。。如果未加引号,则会产生错误:
    术语“LOTR\u TT”无法识别为cmdlet、函数、脚本文件或可操作程序的名称。
    。这是你意想不到的结果吗?