Интеллектуальная обработка атрибутов при извлечении текстового значения xml из XML с помощью PowerShell.

Чтобы получить значение элемента XML в powershell, мы можем просто записать путь, обрабатывая элементы, как если бы они были свойствами объекта PowerShell; то есть $xml.RootElement.ChildElement.GrandChild.

Однако, если интересующий нас элемент имеет связанный атрибут, чтобы получить текстовое значение, нам нужно перейти к текстовому узлу; то есть $xml.RootElement.ChildElement.GrandChild.'#text'.

К сожалению, когда у элемента нет атрибута, мы не можем использовать текстовый узел; т. е. в этом сценарии $xml.RootElement.ChildElement.GrandChild.'#text' не работает.

Clear-Host
$example = [xml](@"
<demo>
    <element attribute='1'>10</element>
    <element>20</element>
</demo>
"@)

"just the element"
$example.demo.element 
"element's text"
$example.demo.element.'#text' 

Я написал неприятный обходной путь для этого, но подозреваю, что это неправильный подход / что у PowerShell есть более элегантный способ решить эту проблему.

Мой неприятный обходной путь:

function Get-TextNode {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        $xmlElement
    )
    process {
        if($xmlElement.Attributes.Count -eq 0) {
            $xmlElement
        } else {
            $xmlElement.'#text'
        }
    }
}

$example.demo.element | Get-TextNode 

person JohnLBevan    schedule 03.10.2016    source источник
comment
пс. Я заметил, что добавление $xmlElement.GetType() к моей команде показывает, что тип элемента изменяется в зависимости от того, присутствуют ли какие-либо атрибуты; то есть если они есть то XmlElement, если нет то String..   -  person JohnLBevan    schedule 03.10.2016


Ответы (1)


Функция SelectNodes решает эту проблему:

i.e.

$example.SelectNodes('/demo/element').'#text'

or

$example.SelectNodes('/demo/element/text()').Value

работать, как ожидалось.

Также возможно обновить узлы следующим образом:

Clear-Host

$example = [xml](@"
<demo>
    <x>5</x>
    <element attribute='1'>10</element>
    <element>20</element>
</demo>
"@)

$example.OuterXml
#Result: <demo><x>5</x><element attribute="1">10</element><element>20</element></demo>

$example.SelectNodes('/demo/element/text()') | %{ 
    $_.value = $_.ParentNode.ParentNode.SelectSingleNode('./x/text()').Value  
}

$example.OuterXml
#Result: <demo><x>5</x><element attribute="1">5</element><element>5</element></demo>
person JohnLBevan    schedule 03.10.2016