Powershell HasChildNodes верен для текста?

pretzelb спросил: 10 мая 2018 в 04:18 в: xml

При работе с объектами XML в Powershell, если HasChildNodes возвращают true, если элемент имеет только текстовые данные, а не другой элемент? Не существует способа идентифицировать элементы, у которых нет реальных элементов под ними?

В приведенном ниже примере я надеялся, что элемент Parameter_Section вернет true для наличия дочерних элементов, но я бы не ожидал, что элементы внутри, чтобы вернуть true, если у них были данные. Например, SCM_Included, SendToApp и WF_Start возвращают true, потому что у них есть текст. В определении говорится: "Получает значение, указывающее, имеет ли этот узел какие-либо дочерние узлы". Означает ли это, что текст или данные считаются дочерним узлом?

Я разбираю кучу файлов XML InfoPath, и я надеялся, что сможет игнорировать родительские элементы, такие как Parameter_Section, которые служат только для организации (InfoPath называет их "секциями") дочерними элементами, которые фактически хранят данные (которые являются полями в InfoPath).

function ReadAllNodes ($node) {
foreach ($childnode in $node.ChildNodes)
{
    [string] $path = Get-XPath($childnode)
    [string] $nt = $childnode.NodeType
    [string] $hc = $childnode.HasChildNodes
    [string] $name = $childnode.Name
    [string] $val = $childnode.Value
    [string] $txt = $childnode.'#text'    Write-Host ("Name={0}, path={1}, type={2}, hc={3}, val={4}, txt={5}" -f $name, $path, $nt, $hc,$val,$txt)
}foreach ($cn in $childnode) {
    ReadAllNodes $cn
    }
}$Xml = @"
<?xml version="1.0" encoding="utf-8"?>
<myFields>
    <Parameter_Section>
        <Approval_Mode />
        <SCM_Included>n</SCM_Included>
        <ApprovalCompleteDateTime />
        <ApprovalCompleteDateStr />
        <SendToApp>No</SendToApp>
        <WF_Start>0</WF_Start>
        <QuoteAttachCount>0</QuoteAttachCount>
        <TestEmail />
        <TestMessage />
        <IsCurrentUserRequestor>true</IsCurrentUserRequestor>
        <CanCurrentUserApprove>Approve</CanCurrentUserApprove>
    </Parameter_Section>
</myFields>
"@$content = New-Object -TypeName XML
$content.LoadXml($Xml)
[System.Xml.XmlElement] $root = $content.get_DocumentElement()ReadAllNodes $root    Name=Parameter_Section, path=/myFields/Parameter_Section, type=Element, hc=True, val=, txt=
Name=Approval_Mode, path=/myFields/Parameter_Section/Approval_Mode, type=Element, hc=False, val=, txt=
Name=SCM_Included, path=/myFields/Parameter_Section/SCM_Included, type=Element, hc=True, val=, txt=n
Name=ApprovalCompleteDateTime, path=/myFields/Parameter_Section/ApprovalCompleteDateTime, type=Element, hc=False, val=, txt=
Name=ApprovalCompleteDateStr, path=/myFields/Parameter_Section/ApprovalCompleteDateStr, type=Element, hc=False, val=, txt=
Name=SendToApp, path=/myFields/Parameter_Section/SendToApp, type=Element, hc=True, val=, txt=No
Name=WF_Start, path=/myFields/Parameter_Section/WF_Start, type=Element, hc=True, val=, txt=0
Name=QuoteAttachCount, path=/myFields/Parameter_Section/QuoteAttachCount, type=Element, hc=True, val=, txt=0
Name=TestEmail, path=/myFields/Parameter_Section/TestEmail, type=Element, hc=False, val=, txt=
Name=TestMessage, path=/myFields/Parameter_Section/TestMessage, type=Element, hc=False, val=, txt=
Name=IsCurrentUserRequestor, path=/myFields/Parameter_Section/IsCurrentUserRequestor, type=Element, hc=True, val=, txt=true
Name=CanCurrentUserApprove, path=/myFields/Parameter_Section/CanCurrentUserApprove, type=Element, hc=True, val=, txt=Approve
Name=#text, path=/myFields/Parameter_Section/CanCurrentUserApprove/#text, type=Text, hc=False, val=Approve, txt=

2 ответа

Есть решение
Mathias R. Jessen ответил: 10 мая 2018 в 04:43

Означает ли это, что текст или данные считаются дочерним узлом?

Да, действительно.

Строка "Утвердить" внутри сам по себе является узлом <CanCurrentUserApprove>. Как и следовало ожидать, вы можете получить доступ к текстовому узлу с помощью свойства XmlText.

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

$content.SelectNodes('//CanCurrentUserApprove')[0].ChildNodes[0]
pretzelb ответил: 10 мая 2018 в 06:53
Кажется, я вижу одну причину, которая меня так смутила. Моя петля показывает только текстовый узел для последнего в списке. Если бы цикл показал текстовый узел для всех остальных элементов, это могло бы быть более очевидным. Мне нужно выяснить, могу ли я исправить этот цикл. Name=CanCurrentUserApprove, path=/myFields/Parameter_Section/CanCurrentUserApprove, type=Element, hc=True, val=, txt=Approve Name=#text, path=/myFields/Parameter_Section/CanCurrentUserApprove/#text, type=Text, hc=False, val=Approve, txt=
mklement0 ответил: 11 мая 2018 в 11:15

Похоже, вы хотите протестировать дочерние элементы , а не узлы , потому что текст, казалось бы, содержащийся внутри элемента, действительно является дочерним узлом типа Text.

Пока вы могли проверять XML-элементы отдельно [1] , проще используйте запрос XPath с помощью командлета Select-Xml:

Ниже перечислены все элементы, у которых нет дочерних элементов , и возвращает те, чей код .InnerText непусто, подразумевая, что они "содержат текст":

Select-Xml -XPath '//*[count(*)=0] and text()' -Content $Xml |
  Select-Object Node, @{ n='Text'; e={ $_.Node.InnerText } }

С вашим образцом XML приведенное выше дает:

Node                   Text
----                   ----
SCM_Included           n
SendToApp              No
WF_Start               0
QuoteAttachCount       0
IsCurrentUserRequestor true
CanCurrentUserApprove  Approve
  • //*[count(*)=0] соответствует только элементы любого имени (*), у которых нет дочерних элементов (count(*)=0 >), где-нибудь в документе //.

  • and text() ограничивает совпадения с элементами, чей код .InnerText Значение свойства не пусто.

    • Примечание: дочерние узлы элемента без element , у которых есть непустое свойство .InnerText, не обязательно s имеет только дочерний узел single типа Text; могут быть дочерние узлы multiple , содержащие любые сочетания типов Text, EntityReference и CDATASection, которые .InnerText объединяется для создания одной строки.
  • Вызов Select-Object создает пользовательские объекты, каждый из которых имеет свойство .Node сопоставленный элемент XML и чье свойство .Text содержит значение .InnerText этого элемента.


[1] Это на самом деле нетривиальный для надежный контроль заданного элемента для отсутствия элементов , как Матиас Р. Джессен a> указывает; в PSv3 + вы можете использовать следующее:

$elem.ChildNodes.NodeType -notcontains 'Element'

Чтобы дополнительно проверить, содержит ли такой элемент "текст" (имеет неэлементные дочерние узлы, которые [объединяются] имеют непустое текстовое представление):

$elem.ChildNodes.NodeType -notcontains 'Element' -and $elem.InnerText -ne '' 

Вы можете опустить -ne '' в конце, потому что любая непустая строка в PowerShell является "правдой".