Я пытаюсь организовать XML-документ, который содержит информацию о драйвере. Вот пример того, с чем я работаю:
<?xml version="1.0" encoding="utf-8"?>
<IncludeFragment xmlns:p="http://schemas.microsoft.com/someschema">>
<FFUDriver>
<Component>
<Package>
<p:PackageName>Intel.Display.Driver</PackageName>
<p:PackageFeedName>Feed</PackageFeedName>
<p:Version>10.24.0.1638</Version>
<p:Flavor>release</Flavor>
</Package>
</Component>
</FFUDriver>
<FFUDriver>
<Component>
<Package>
<p:PackageName>Intel.Audio.Driver</PackageName>
<p:PackageFeedName>Feed</PackageFeedName>
<p:Flavor>release</Flavor>
<p:Version>10.24.0.1638</Version>
<p:CabName>Intel.Audio.cab</CabName>
</Package>
</Component>
</FFUDriver>
</IncludeFragment>
Мне нужно отсортировать элементы каждого пакета в следующем порядке:
- PackageName
- PackageFeedName
- Версия
- Ароматизатор
Некоторые элементы пакетов уже находятся в правильном порядке, некоторые нет, как в моем примере XML-кода. Также каждый пакет должен быть отсортирован в алфавитном порядке на основе PackageName. Я новичок в работе с XML в PowerShell и не могу понять, как этого добиться.
Другое требование - найти и удалить все элементы <CabName>
. Я вроде понял это. Приведенный ниже код, к сожалению, удаляет все дочерние элементы элемента <Package>
, если один из его дочерних элементов равен <CabName>
. Я не могу понять синтаксис для выбора и удаления только <CabName>
.
$Path = 'C:\Drivers.xml'
$xml = New-Object -TypeName XML
$xml.Load($Path)
$xml.SelectNodes('//Package[CabName]') | ForEach-Object {
$_.ParentNode.RemoveChild($_)
}
$xml.Save('C:\Test.xml')
ОБНОВЛЕНИЕ: С помощью Ansgar Wiechers, вот готовый код. Я обновил пример XML-данных, добавив в него пространство имен, поскольку некоторые документы, с которыми я работаю, содержат их. Код ниже обрабатывает пространства имен. Я надеюсь, что это поможет кому-то еще с подобной проблемой / вопросами!
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $True, Position = 0)]
[ValidateScript({
$_ = $_ -replace '"', ""
if (-Not (Test-Path -Path $_ -PathType Leaf))
{
Throw "`n `n$_ `n `nThe specified file or path does not exist. Check the file name and path, and then try again."
}
return $True
})]
[System.String]$XMLPath,
[Parameter(Mandatory = $False, Position = 1)]
[System.String]$nsPrefix = "p",
[Parameter(Mandatory = $False, Position = 2)]
[System.String]$nsURI = "http://schemas.microsoft.com/someschema"
)
# Remove quotes from full path name, if they are present
$XMLPath = $XMLPath -replace '"', ""
$xml = New-Object -TypeName XML
$xml.Load($XMLPath)
$ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$ns.AddNamespace($nsPrefix, $nsURI)
# Delete all CabName elements
$xml.SelectNodes('//p:CabName', $ns) | ForEach-Object {
$_.ParentNode.RemoveChild($_) | Out-Null
}
# Sort each Package element's child nodes based on custom order
$SortList = 'p:PackageName', 'p:PackageFeedName', 'p:Version', 'p:Flavor'
$xml.SelectNodes('//Package') | ForEach-Object {
$parent = $_
$SortList | ForEach-Object {
$child = $parent.RemoveChild($parent.SelectSingleNode("./$_", $ns))
$parent.AppendChild($child)
}
} | Out-Null
# Sort each Package element in alphabetical order based on its child node PackageName
$PackageNameList = $xml.SelectNodes('//p:PackageName', $ns) | Select-Object -Expand '#text' | Sort-Object
$xml.SelectNodes('//IncludeFragment') | ForEach-Object {
$parent = $_
$PackageNameList | ForEach-Object {
$child = $parent.RemoveChild($parent.SelectSingleNode("./FFUDriver[Component/Package/p:PackageName/text()='$_']", $ns))
$parent.AppendChild($child)
}
} | Out-Null
$XMLPath = $XMLPath -replace ".xml", "_sorted.xml"
$xml.Save($XMLPath)
Write-Host "`nSorting complete. Sorted XML document saved under $XMLPath" -ForegroundColor Green