我正在尝试在 XML 文件中添加新元素。下面是 XML 文件。我的目标是添加几个新的 Svc,其属性为 Name、Displayname、Activ、CommadState、Status。
由于我的 Svc 元素没有 ID 或其他东西,我无法添加然后编辑我必须直接添加正确的值
我已经尝试过这样的操作,但它说我正在尝试调用空值表达式。
$drive = "E:"
$filePath = Get-Content $drive\Alarm\Services\ProgWatch\ProgWatchServices.xml
$doc = New-Object System.Xml.XmlDocument
$doc.Load($filePath)
$child = $doc.CreateElement("Svc")
$doc.DocumentElement.AppendChild($child)
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSvc xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Svc>
<Name>Respus</Name>
<Displayname>Respus</Displayname>
<Activ>true</Activ>
<CommadState>NoCommand</CommadState>
<Status>Running</Status> </Svc> <Svc>
<Name>AlarmUS</Name>
<Displayname>AlarmUS</Displayname>
<Activ>true</Activ>
<CommadState>NoCommand</CommadState>
<Status>Running</Status> </Svc> <Svc>
<Name>asProgWatchGuard</Name>
<Displayname>Prog Watch Guardian</Displayname>
<Activ>true</Activ>
<CommadState>NoCommand</CommadState>
<Status>Running</Status>
</Svc>
<Svc>
<Name>asBackup</Name>
<Displayname>Data Backup</Displayname>
<Activ>true</Activ>
<CommadState>NoCommand</CommadState>
<Status>Running</Status>
</Svc>
</ArrayOfSvc>
这看起来像 PowerShell。这是使用 Xml Linq 网络库的代码
using assembly System.Xml.Linq
$filename = "c:\temp\test.xml"
$doc = [System.Xml.Linq.XDocument]::Load($filename)
$arrayOfSvc = $doc.Root
$child = [System.Xml.Linq.XElement]::new([System.Xml.Linq.XName]::Get('Svc'))
$arrayOfSvc.Add($child)
$doc
tl;博士
要立即修复,请将
.Load()
更改为 .LoadXml()
一个健壮且更高效的方法是将文件路径直接传递给
.Load()
方法:
$drive = "E:"
# Note: Be sure to use a *full path*.
$filePath = "$drive\Alarm\Services\ProgWatch\ProgWatchServices.xml"
$doc = New-Object System.Xml.XmlDocument
$doc.Load($filePath)
$child = $doc.CreateElement("Svc") # An empty new element - see also below.
$doc.DocumentElement.AppendChild($child)
上面仅创建了一个 empty
<Svc>
元素。使用方法迭代创建所需的结构;例如:
$child = $doc.CreateElement('Svc')
$grandChild1 = $doc.CreateElement('Name')
$grandChild1.InnerText = 'newName'
$grandChild2 = $doc.CreateElement('DisplayName')
$grandChild2.InnerText = 'newDisplayName'
# ...
$null = $child.AppendChild($grandChild1)
$null = $child.AppendChild($grandChild2)
# ...
# Finally, insert the completed new child element into the document
$null = $doc.DocumentElement.AppendChild($child)
XmlDocumentFragment
获取的 .CreateDocumentFragment()
实例,从表示所需结构的 XML string 构造新元素;例如:
$child = $doc.CreateDocumentFragment()
$child.InnerXml = '
<Svc>
<Name>{0}</Name>
<Displayname>{1}</Displayname>
<Activ>{2}</Activ>
<CommadState>{3}</CommadState>
<Status>{4}</Status>
</Svc>
' -f 'newName', 'newDisplayName', 'false', 'NoCommand', 'Suspended'
# Insert the completed new child element into the document
$null = $doc.DocumentElement.AppendChild($child)
您的
$filePath
变量 - 尽管其名称 - 包含 XML 文本,因为您在文件路径中使用了 Get-Content
。
.LoadXml()
而不是 .Load()
类的 System.Xml.XmlDocument
方法(您可以在 PowerShell 中将其称为 [xml]
)。
但是,最好避免这种从文件加载 XML 的两步方法,原因如下:
效率:直接使用
.Load()
方法与文件路径只需要一次调用。
字符编码:
.Load()
方法在读取时默认为UTF-8并且特别尊重XML声明中的encoding
属性(例如,<?xml version="1.0" encoding="ISO-8859-1"?>
)(如果字符编码是不同的) .
相比之下,
Get-Content
不会这样做(它从不解释文件的内容),并且在Windows PowerShell中默认为 ANSI 编码,即系统的活动旧版 ANSI 代码页隐含的编码(相比之下,PowerShell(核心)7+现在值得称赞的是,所有 cmdlet 都默认为(无 BOM)UTF-8。
Get-Content
可能会误解您的 XML 文件。
[xml]
型加速器结合使用,
Get-Content
是诱人,但不稳健。如果您愿意假设
Get-Content
不会误解 XML 文件,或者您知道实际编码并通过
-Encoding
指定它,则可以使用以下 shortcut;请注意使用
-Raw
来读取整个文件作为一个整体,这比默认情况下执行的逐行读取快得多)
Get-Content
稳健简明表述(如顶部所示)是:
# Convenient, but NOT ROBUST
# May need an -Encoding argument.
$doc = [xml] (Get-Content -Raw $filePath)