如何使用PowerShell编辑和保存XML节点

时间:2021-05-19 07:15:35

I cannot seem to get this to work. I want to use PowerShell to select all nodes of a particular type, edit them, then save back to disk.

我似乎做不到。我想使用PowerShell选择特定类型的所有节点,编辑它们,然后保存回磁盘。

Here is the starting XML file:

下面是开始的XML文件:

<Cars>
  <Car>Car1</Car>
  <Car>Car2</Car>
</Cars>

Here is the file after being modified:

以下是修改后的文件:

<Cars>
  <Car Text="Car1"></Car>
  <Car Text="Car2"></Car>
</Cars>

Have tried:

尝试:

[xml]$xaml = Get-Content -Path "C:\Test\TranslationUtility\cars.xml" |
             Select-Xml -XPath "//Car" |
             Write-Host $_.InnerText;

3 个解决方案

#1


2  

The code you posted should throw a bunch of errors, because Get-Content (without the parameter -Raw) produces an array of strings, each of which is invalid XML by itself. Feeding that into Select-Xml doesn't work. Also, your use of the [xml] type accelerator and Write-Host is wrong.

您发布的代码应该会抛出一系列错误,因为Get-Content(没有参数-Raw)生成一个字符串数组,每个字符串本身都是无效的XML。将这些输入到Select-Xml中是行不通的。此外,使用[xml]类型加速器和Write-Host是错误的。

Rule of thumb:

经验法则:

  • If you want to use Select-Xml let it read the file by itself (via its -Path parameter):

    如果您想使用Select-Xml,让它自己读取文件(通过它的-Path参数):

    $xpath   = '//Car'
    $xmlfile = 'C:\Test\TranslationUtility\cars.xml'
    
    Select-Xml -Xpath $xpath -Path $xmlfile
    
  • If you want to use Get-Content and the [xml] type accelerator use the SelectNodes() method:

    如果您想使用Get-Content和[xml]类型加速器,请使用SelectNodes()方法:

    $xpath   = '//Car'
    $xmlfile = 'C:\Test\TranslationUtility\cars.xml'
    
    [xml]$xml = Get-Content $xmlfile
    $xml.SelectNodes($xpath)
    

However, that alone won't allow you to achieve your desired result, because you want to manipulate XAML files. Please don't omit such crucial information from your questions. I'm only aware because I was just about to respond to your previous question when you deleted it.

然而,单凭这一点,您无法实现所需的结果,因为您希望操作XAML文件。请不要在你的问题中漏掉这些重要的信息。我知道,因为我正要回答你之前的问题,你把它删除了。

XAML files are always using namespaces, so you must use a namespace manager to take care of that, like this:

XAML文件总是使用名称空间,因此必须使用名称空间管理器来处理这个问题,如下所示:

$xpath   = '//ns:Car'
$xmlfile = 'C:\Test\TranslationUtility\cars.xml'
$ns = @{'ns' = 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'}

Select-Xml -Xpath $xpath -Path $xmlfile -Namespace $ns

or like this:

或者像这样:

$xpath   = '//ns:Car'
$xmlfile = 'C:\Test\TranslationUtility\cars.xml'

[xml]$xml = Get-Content $xmlfile

$nsm = New-Object Xml.XmlNamespaceManager($xml.NameTable) $nsm.AddNamespace("ns", $xml.DocumentElement.NamespaceURI)

$xml.SelectNodes($xpath, $nsm)

Since you want to modify the XML data I'd probably go with the latter approach. That allows you to add an attribute like this:

由于您希望修改XML数据,我可能会采用后一种方法。这允许您添加如下属性:

$i = 1
$xml.SelectNodes($xpath, $nsm) | ForEach-Object {
    [void]$_.SetAttribute('Text', "Car$i")
    $i++
}

Save the modified XML via the Save() method:

通过Save()方法保存修改后的XML:

$xml.Save('C:\path\to\output.xml')

#2


1  

You need to iterate through the results in the pipeline. You have more than one result from searching for cars. At the end, you will want to have % {$_.Node.Text} instead of Write-Host $_.InnerText;

您需要在管道中迭代结果。你搜索汽车的结果不止一个。最后,您将希望拥有% {$_.Node。Text}代替Write-Host $_.InnerText;

The % is a shortcut for For-Each Object. So it basically loops through each entry and displays the information you need.

%是每个对象的快捷方式。所以它基本上循环遍历每个条目并显示你需要的信息。

#3


1  

Here is how I'd approach this.

这就是我的方法。

First, you get the content from the xml file, then you use SelectNodes to find the nodes you want, you iterate them, create the attribute and assign a value.

首先,从xml文件中获取内容,然后使用SelectNodes查找所需的节点,迭代它们,创建属性并分配值。

Once this is done, all that remains is to save the xml back.

完成之后,剩下的就是保存xml。

[xml]$MyXML = Get-Content 'C:\__tmp\YourXmlFile.xml'

$Cars  = $MyXML.SelectNodes('//Car')

$Cars | foreach {
$TextAttrib = $_.OwnerDocument.CreateAttribute('text') 
$_.Attributes.Append($TextAttrib) |Out-Null;
$_.SetAttribute('text','My Car text...')
}

$MyXML.Save('C:\__tmp\YourXmlFile.xml')

As you can see, mine only write a static text, My Car text... but you can tailor this to suit your needs.

如你所见,我只写一个静态文本,我的汽车文本…但你可以根据自己的需要来定制。

#1


2  

The code you posted should throw a bunch of errors, because Get-Content (without the parameter -Raw) produces an array of strings, each of which is invalid XML by itself. Feeding that into Select-Xml doesn't work. Also, your use of the [xml] type accelerator and Write-Host is wrong.

您发布的代码应该会抛出一系列错误,因为Get-Content(没有参数-Raw)生成一个字符串数组,每个字符串本身都是无效的XML。将这些输入到Select-Xml中是行不通的。此外,使用[xml]类型加速器和Write-Host是错误的。

Rule of thumb:

经验法则:

  • If you want to use Select-Xml let it read the file by itself (via its -Path parameter):

    如果您想使用Select-Xml,让它自己读取文件(通过它的-Path参数):

    $xpath   = '//Car'
    $xmlfile = 'C:\Test\TranslationUtility\cars.xml'
    
    Select-Xml -Xpath $xpath -Path $xmlfile
    
  • If you want to use Get-Content and the [xml] type accelerator use the SelectNodes() method:

    如果您想使用Get-Content和[xml]类型加速器,请使用SelectNodes()方法:

    $xpath   = '//Car'
    $xmlfile = 'C:\Test\TranslationUtility\cars.xml'
    
    [xml]$xml = Get-Content $xmlfile
    $xml.SelectNodes($xpath)
    

However, that alone won't allow you to achieve your desired result, because you want to manipulate XAML files. Please don't omit such crucial information from your questions. I'm only aware because I was just about to respond to your previous question when you deleted it.

然而,单凭这一点,您无法实现所需的结果,因为您希望操作XAML文件。请不要在你的问题中漏掉这些重要的信息。我知道,因为我正要回答你之前的问题,你把它删除了。

XAML files are always using namespaces, so you must use a namespace manager to take care of that, like this:

XAML文件总是使用名称空间,因此必须使用名称空间管理器来处理这个问题,如下所示:

$xpath   = '//ns:Car'
$xmlfile = 'C:\Test\TranslationUtility\cars.xml'
$ns = @{'ns' = 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'}

Select-Xml -Xpath $xpath -Path $xmlfile -Namespace $ns

or like this:

或者像这样:

$xpath   = '//ns:Car'
$xmlfile = 'C:\Test\TranslationUtility\cars.xml'

[xml]$xml = Get-Content $xmlfile

$nsm = New-Object Xml.XmlNamespaceManager($xml.NameTable) $nsm.AddNamespace("ns", $xml.DocumentElement.NamespaceURI)

$xml.SelectNodes($xpath, $nsm)

Since you want to modify the XML data I'd probably go with the latter approach. That allows you to add an attribute like this:

由于您希望修改XML数据,我可能会采用后一种方法。这允许您添加如下属性:

$i = 1
$xml.SelectNodes($xpath, $nsm) | ForEach-Object {
    [void]$_.SetAttribute('Text', "Car$i")
    $i++
}

Save the modified XML via the Save() method:

通过Save()方法保存修改后的XML:

$xml.Save('C:\path\to\output.xml')

#2


1  

You need to iterate through the results in the pipeline. You have more than one result from searching for cars. At the end, you will want to have % {$_.Node.Text} instead of Write-Host $_.InnerText;

您需要在管道中迭代结果。你搜索汽车的结果不止一个。最后,您将希望拥有% {$_.Node。Text}代替Write-Host $_.InnerText;

The % is a shortcut for For-Each Object. So it basically loops through each entry and displays the information you need.

%是每个对象的快捷方式。所以它基本上循环遍历每个条目并显示你需要的信息。

#3


1  

Here is how I'd approach this.

这就是我的方法。

First, you get the content from the xml file, then you use SelectNodes to find the nodes you want, you iterate them, create the attribute and assign a value.

首先,从xml文件中获取内容,然后使用SelectNodes查找所需的节点,迭代它们,创建属性并分配值。

Once this is done, all that remains is to save the xml back.

完成之后,剩下的就是保存xml。

[xml]$MyXML = Get-Content 'C:\__tmp\YourXmlFile.xml'

$Cars  = $MyXML.SelectNodes('//Car')

$Cars | foreach {
$TextAttrib = $_.OwnerDocument.CreateAttribute('text') 
$_.Attributes.Append($TextAttrib) |Out-Null;
$_.SetAttribute('text','My Car text...')
}

$MyXML.Save('C:\__tmp\YourXmlFile.xml')

As you can see, mine only write a static text, My Car text... but you can tailor this to suit your needs.

如你所见,我只写一个静态文本,我的汽车文本…但你可以根据自己的需要来定制。