Powershell HasChildNodes适用于文本吗?

时间:2018-06-03 17:58:42

标签: xml powershell xml-parsing

在Powershell中使用XML对象时,如果元素只有文本数据而不是另一个元素,HasChildNodes是否会返回true?难道没有办法识别其下没有任何实际元素的元素吗?

鉴于下面的示例,我希望元素Parameter_Section对于生孩子会返回true,但我不希望里面的元素如果有数据也会返回true。例如,SCM_Included,SendToApp和WF_Start都返回true,因为它们有文本。定义说"获取一个值,该值指示此节点是否具有任何子节点"。这是否意味着文本或数据被视为子节点?

我正在解析一堆InfoPath XML文件,我希望能够忽略像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 个答案:

答案 0 :(得分:3)

  

这是否意味着文本或数据被视为子节点?

是的,的确如此。

字符串&#34;批准&#34; <CanCurrentUserApprove>节点内部本身是XmlText节点。正如您所料,您可以通过ChildNodes属性访问文本节点。

尝试以下示例:

$content.SelectNodes('//CanCurrentUserApprove')[0].ChildNodes[0]

答案 1 :(得分:2)

听起来你想测试子元素,而不是节点,因为看似包含在元素中的文本确实是一个子节点类型为Text

虽然可以单独检查XML元素 [1] ,通过Select-Xml cmdlet

更容易使用XPath查询

以下内容查找没有子元素的所有元素,并返回.InnerText属性为非空的元素,这意味着它们&#34;包含文本&#34;:

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)的元素1}}。

  • //将匹配限制为and text()属性值非空的元素。

    • 注意:没有元素子节点且具有非.InnerText属性的元素节点不必总是只有单个类型为{{1}的子节点}};可能有多个子节点包含.InnerTextTextText的任意组合,EntityReference连接形成单个字符串。< / LI>
  • CDATASection调用构造自定义对象,其每个.InnerText属性包含匹配的XML元素,其Select-Object属性包含该元素&#39; s {{1价值。

[1] 元素孩子缺席的强健检查确实非常重要,因为{{ 3}}指出;在PSv3 +中,您可以使用以下内容:

.Node

另外检查这样的元素是否包含文本&#34; (具有[组合]具有非空文本表示的非元素子节点):

.Text

最后可以省略.InnerText,因为PowerShell中的任何非空字符串都是&#34; truthy&#34;。