我有一些XML,希望能够覆盖STATUS标记。
外观:
<START>
<EXAMPLE>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
</EXAMPLE>
</START>
我想要它的样子:
<START>
<EXAMPLE>
<THINGS>
<STUFF>
<STATUS>Open</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>NA</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Closed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Open</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>Open</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<STUFF>
<STATUS>NA</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
</EXAMPLE>
</START>
有了这段代码,我可以将每个STATUS标记更改为正确的值,当我在脚本运行后仅运行$XMLStatus后检查控制台时,它会显示出它应该显示的所有内容,但当我在记事本中打开XML时就不会了。它仍然将所有内容显示为Not_Reviewed。我不知道我在这里做错了什么,我们非常感谢你的帮助。
[xml]$xmldoc = Get-Content -Path 'C:test.xml'
$XMLStatus = $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS
$XMLcount = 0
foreach($one in $XMLStatus[$XMLcount]){
foreach($status in $one){
$one = $myvalue
Switch ($one){
1 {$status = "Open"; break;}
2 {$status = "Closed"; break;}
3 {$status = "NA"; break;}
default {"Open"}
}
$XMLStatus[$XMLcount] = $status
}
}
$xmldoc.Save('C:test.xml')
$XMLcount++
不需要通过索引访问单个元素。使用XPath查询将所有STATUS元素选择到XPathNodeList中。使用foreach循环对其进行迭代,并使用switch语句更改InnerText属性。像这样,
[xml]$xmldoc = get-content c:whatever.xml
# Select all STATUS elements. NB: element names in XPath are case-sensitive
$nl = $xmldoc.selectnodes('/START/EXAMPLE/THINGS/STUFF/STATUS')
# Loop through the nodes and change InnerText numbers to string values
foreach($n in $nl) {
switch($n.InnerText){
1 {$s = "Open"; break;}
2 {$s = "Closed"; break;}
3 {$s = "NA"; break;}
default {$s = "Open"}
}
$n.InnerText = $s
}
# Print the results on console
$xmldoc.Save([console]::out)
在PowerShell中并不经常使用xml,但我想我知道发生了什么。
您的xml被复制粘贴得很有趣,并使其无效。你丢失了一些标签。
正因为如此,我采取了一些自由,做出了自己的决定。
<START>
<EXAMPLE>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
</EXAMPLE>
</START>
首先,您没有在文件中看到值的更改,是因为您没有将这些更改保存到文件中。您将$xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS
的值放入一个变量中,然后使用该变量,只对该变量进行更改,而不是对原始文档变量进行更改。
其次,在您的示例中,$myvalue
没有设置在任何位置,所以在您的交换机中,所有内容都将默认为您的默认情况。
第三,默认情况下除了打印";打开";到stdout。
最后,您需要避免试图通过获取对象的值并更改该值来更改值。我知道这听起来很令人困惑,所以让我们来举一个例子。
我们认为我们想要修改的是$xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS[i]
的值,但这就是我们错的地方。我们不想设置.STATUS[i]
的值,因为它只是一个字符串对象,当您运行它并查看TypeName时,您可以看到它。
$xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS[0] | Get-Member
实际上,我们想要修改的是STATUS
属性,它位于STUFF
元素中。所以如果你做这个
$xmldoc.START.EXAMPLE.THINGS.STUFF[0] | Get-Member
您会注意到,TypeName是System.Xml.XmlElement
,那里有一个名为STATUS
的属性,在definition列中,我们看到它是一个字符串,我们知道我们可以获得这个值,并将其设置为{get;set;}
以供参考,这些被称为getter和setter。
为了修改该值,我们需要设置STATUS
属性,如下所示``$xmldoc.START.EXAMPLE.THINGS.STUFF[0].STATUS=";不管什么"`
所以经过一些修改,这就是我的想法。评论是我做出改变的地方。
[xml]$xmldoc = "
<START>
<EXAMPLE>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
</EXAMPLE>
</START>"
#set myyvalue
$myvalue = 1
# removed this var completely
#$XMLStatus = $xmldoc.START.EXAMPLE.THINGS.STUFF.STATUS
$XMLcount = 0
# for the foreach, we want to work with each object in the STUFF array
# I also removed the extra foreach, as it seemed unnecessary
foreach($one in $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS)
{
# made the switch, switch off of $myvalue
Switch ($myvalue){
1 {$status = "Open"; break;}
2 {$status = "Closed"; break;}
3 {$status = "NA"; break;}
# fixed the default case to properly set the var
default {$status = "Open"}
}
$xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS = $status
}
$xmldoc.Save('C:temptest.xml')
$XMLcount++
如果你想要一个通过运行一次遍历所有内容的版本,你可以得到STUFF
的长度,并使用while
循环
[xml]$xmldoc = "
<START>
<EXAMPLE>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
<THINGS>
<STUFF>
<STATUS>Not_Reviewed</STATUS>
<DETAILS>1111 2222 3333 4444 5555 6666 7777 8888</DETAILS>
</STUFF>
</THINGS>
</EXAMPLE>
</START>"
$myvalue = 1
$numberOfElements = $xmldoc.START.EXAMPLE.THINGS.Length
$XMLcount = 0
while($XMLcount -lt $numberOfElements)
{
foreach($one in $xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS)
{
Switch ($myvalue){
1 {$status = "Open"; break;}
2 {$status = "Closed"; break;}
3 {$status = "NA"; break;}
default {$status = "Open"}
}
$xmldoc.START.EXAMPLE.THINGS.STUFF[$XMLcount].STATUS = $status
}
$XMLcount++
}
$xmldoc.Save('C:temptest.xml')