Метод SelectNodes в xml с использованием PowerShell-скрипта не возвращает узлы (проблемы с пространством имен?)

Вопрос или проблема

Я пытаюсь отредактировать XML-документ с помощью скрипта PowerShell.

Вот XML-файл.

<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
          http://maven.apache.org/xsd/settings-1.0.0.xsd">

    <servers>
        <server>
            <id>libs-release</id>
            <username>USERNAME</username>
            <password>PASSWORD</password>
        </server>
        <server>
            <id>plugins-release</id>
            <username>USERNAME</username>
            <password>PASSWORD</password>
        </server>
        <server>
            <id>0eb153056152</id>
            <username>USERNAME</username>
            <password>PASSWORD</password>
        </server>

    </servers>

</settings>

Вот скрипт PowerShell.

$file = "C:\Users\XXXXXXXXX\Downloads\config\maven_settings.xml"

[xml]$xml = Get-Content $file

$xml.SelectNodes("//username")

Скрипт не возвращает никаких узлов. Но когда я убираю атрибуты тега <settings>, он работает и возвращает необходимые узлы. Это проблема с пространствами имен? Как мне решить это, оставив атрибуты пространств имен в оригинальном XML-документе?

Вы можете попробовать следующее:

$xml.settings.servers.server.username

Однако, как отметил @Frank Thomas в комментариях, cmdlet Select-Xml лучше по сравнению с вышеупомянутым подходом (вам нужно учитывать иерархию).

То, что Фрэнк и участник ссылочного указания ‘Reddy’ показали (что я также упоминал в этом ответе, но убрал, как только его сообщение появилось), является разумным путем. Тем не менее, если вы хотите использовать SelectNodes, то:

$MyXml.SelectNodes('/*/*/*')
# Результаты
<#
id              username password
--              -------- --------
libs-release    USERNAME PASSWORD
plugins-release USERNAME PASSWORD
0eb153056152    USERNAME PASSWORD
#>

($MyXml.SelectNodes('/*/*/*')).username
# Результаты
<#
username
--------
USERNAME
USERNAME
USERNAME
#>

С учетом всего. Это просто как подход ссылочного указания участника, только без необходимости явно вводить все имена членов.

Вам нужно установить пространство имен перед выбором узлов\значений и т.д.

Попробуйте следующее

$Namespace = @{
        nsa = ($xmlDoc.GetEnumerator() | ? { -not  [string]::IsNullOrEmpty($_.NamespaceURI) } ).NamespaceURI
    }

затем

Select-Xml -XPath $xpath -Xml $xmlDoc -Namespace $Namespace

“nsa” – любое слово по вашему усмотрению.
с SelectNodes я не смог использовать пространство имен, хотя эта перегрузка указана в документах MS

Ответ или решение

При работе с XML-документами в PowerShell, одной из частых проблем, с которой сталкиваются разработчики, являются вопросы, связанные с пространствами имен. Ваша ситуация, когда метод SelectNodes не возвращает никаких узлов из-за добавленных пространств имен, является распространенной проблемой. В этом ответе мы рассмотрим, как решить эту проблему, сохранив при этом структуру оригинального XML-документа.

Проблема с пространствами имен

Когда вы определяете XML-документ с пространствами имен, каждое обращение к узлам XML должно учитывать это пространство имен. В вашем случае корневой элемент <settings> объявляет пространство имен, что делает выбор узлов, как, например, <username>, более сложным, если вы не учитываете это пространство.

Решение через SelectNodes с учетом пространства имен

Чтобы использовать метод SelectNodes для выборки узлов с учетом пространств имен, вам необходимо создать объект пространство имен и использовать его в вашем XPath-запросе. Рассмотрим следующий код как пример:

# Загрузка XML из файла
$file = "C:\Users\XXXXXXXXX\Downloads\config\maven_settings.xml"
[xml]$xml = Get-Content $file

# Определим пространство имен
$namespace = @{ "ns" = "http://maven.apache.org/POM/4.0.0" }

# Выбор узлов с использованием пространства имен
$usernames = $xml.SelectNodes("//ns:username", $namespace)

# Вывод результатов
foreach ($username in $usernames) {
    Write-Output $username
}

Альтернативный подход с использованием Select-Xml

Как упоминалось в комментариях, команда Select-Xml также может быть полезной при работе с пространствами имен. Она позволяет напрямую передавать пространство имен в запросе:

# Использование Select-Xml с пространствами имен
$namespace = @{ "ns" = "http://maven.apache.org/POM/4.0.0" }
$usernames = Select-Xml -Path $file -XPath '//ns:username' -Namespace $namespace

# Вывод результатов
foreach ($username in $usernames) {
    Write-Output $username.Node.InnerXml
}

Заключение

Таким образом, для успешного извлечения узлов из XML-документа с пространствами имен в PowerShell, важно всегда учитывать пространства имен при написании XPath-запросов. Ваша проблема может быть решена как с помощью SelectNodes, так и с помощью Select-Xml, в зависимости от ваших предпочтений и специфики задачи.

Рекомендации

  1. Изучите XPath: Понимание синтаксиса XPath, включая поддерживаемые конструкции для работы с пространствами имен, значительно упростит вашу работу с XML-документами.
  2. Тестируйте на небольших примерах: Перед применением более сложных запросов всегда полезно тестировать на меньших наборов данных, чтобы минимизировать количество ошибок.
  3. Используйте документацию: В Microsoft имеется обширная документация по PowerShell и XML, которая поможет вам глубже понять методы работы с данными.

Следуя этим рекомендациям, вы сможете эффективно работать с XML-документами, учитывая все нюансы, связанные с пространствами имен.

Оцените материал
Добавить комментарий

Капча загружается...