Xml Powershell HasChildNodes对于文本是否为true?

Xml Powershell HasChildNodes对于文本是否为true?,xml,powershell,xml-parsing,Xml,Powershell,Xml Parsing,在Powershell中处理XML对象时,如果元素只有文本数据而没有其他元素,则HasChildNodes是否应返回true?是否有一种方法可以识别没有任何实际元素的元素 给出下面的示例,我希望元素参数_部分在有子元素时返回true,但我不希望其中的元素在有数据时也返回true。例如,SCM_Included、SendToApp和WF_Start都返回true,因为它们有文本。定义表示获取一个值,该值指示此节点是否有任何子节点。这是否意味着文本或数据被视为子节点 我正在分析一组InfoPath

在Powershell中处理XML对象时,如果元素只有文本数据而没有其他元素,则HasChildNodes是否应返回true?是否有一种方法可以识别没有任何实际元素的元素

给出下面的示例,我希望元素参数_部分在有子元素时返回true,但我不希望其中的元素在有数据时也返回true。例如,SCM_Included、SendToApp和WF_Start都返回true,因为它们有文本。定义表示获取一个值,该值指示此节点是否有任何子节点。这是否意味着文本或数据被视为子节点

我正在分析一组InfoPath XML文件,我希望能够忽略父元素,如仅用于组织InfoPath的Parameter_Section,将其称为Section—实际上存储数据的子元素,这些数据是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=
这是否意味着文本或数据被视为子节点

是的,的确如此

节点内的字符串Approve本身就是一个XmlText节点。正如您所期望的,您可以通过ChildNodes属性访问文本节点

请尝试以下示例:

$content.SelectNodes('//CanCurrentUserApprove')[0].ChildNodes[0]
这是否意味着文本或数据被视为子节点

是的,的确如此

节点内的字符串Approve本身就是一个XmlText节点。正如您所期望的,您可以通过ChildNodes属性访问文本节点

请尝试以下示例:

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

听起来您想测试子元素,而不是节点,因为元素中似乎包含的文本实际上是text类型的子节点

虽然您可以单独检查XML元素[1] ,通过以下方式使用XPath查询更容易:

以下内容查找没有子元素的所有元素,并返回其.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

文本将匹配限制为.InnerText属性值为非空的元素

注意:没有元素子节点且具有非空的元素节点。InnerText属性不必总是只有一个文本类型的子节点;可能有多个子节点,包括.InnerText连接以形成单个字符串的任何类型的混合文本、EntityReference和CDATA节。 Select对象调用构造自定义对象,每个自定义对象的.Node属性包含一个匹配的XML元素,其.Text属性包含该元素的.InnerText值

[1] 正如所指出的那样,严格检查给定元素是否缺少元素子元素实际上是非常重要的;在PSv3+中,可以使用以下各项:

$elem.ChildNodes.NodeType -notcontains 'Element'
要进一步检查此类元素是否包含文本,以及是否具有具有非空文本表示形式的非元素子节点,请执行以下操作:

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

您可以在结尾省略-ne,因为PowerShell中的任何非空字符串都是真实的。

听起来您想测试子元素,而不是节点,因为元素中似乎包含的文本实际上是text类型的子节点

虽然您可以单独检查XML元素[1] ,通过以下方式使用XPath查询更容易:

以下内容查找没有子元素的所有元素,并返回其.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

文本将匹配限制为.InnerText属性值为非空的元素

注意:没有元素子节点且具有非空的元素节点。InnerText属性不必总是只有一个文本类型的子节点;可能有多个子节点,包括.InnerText连接以形成单个字符串的任何类型的混合文本、EntityReference和CDATA节。 Select对象调用构造自定义对象,每个自定义对象的.Node属性包含一个匹配的XML元素,其.Text属性包含该元素的.InnerText值

[1] 正如所指出的那样,严格检查给定元素是否缺少元素子元素实际上是非常重要的;在PSv3+中,可以使用以下各项:

$elem.ChildNodes.NodeType -notcontains 'Element'
要进一步检查此类元素是否包含文本,以及是否具有具有非空文本表示形式的非元素子节点,请执行以下操作:

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

您可以在结尾省略-ne,因为PowerShell中的任何非空字符串都是真实的。

.NET是真实的。如果项不是null、string.EmptyString或0,则它的计算结果为true。@TheIncorrigible1:这不是问题的根源,但感谢您指出PowerShell中任何非空字符串的真实性-即使它碰巧包含文本字符串False。然而,请注意
这本身不是一个.NET特性;例如,这种松散类型的到布尔值的转换在C中根本不起作用。@mklement0它不仅适用于字符串,而且IIRC同样适用于C最近没有写入任何数据。@InCorrigible1:是的,在PowerShell中,到布尔值的强制适用于任何数据类型,但关键是,这种逻辑取决于每种基于.NET的语言,而不是.NET CLR本身。而且,不,C不支持隐式地将任意类型强制为[bool]。NET是真实的。如果项不是null、string.EmptyString或0,则它的计算结果为true。@TheIncorrigible1:这不是问题的根源,但感谢您指出PowerShell中任何非空字符串的真实性-即使它碰巧包含文本字符串False。但是,请注意,这本身并不是.NET特性;例如,这种松散类型的到布尔值的转换在C中根本不起作用。@mklement0它不仅适用于字符串,而且IIRC同样适用于C最近没有写入任何数据。@InCorrigible1:是的,在PowerShell中,到布尔值的强制适用于任何数据类型,但关键是,这种逻辑取决于每种基于.NET的语言,而不是.NET CLR本身。而且,不,C不支持隐式地将任意类型强制为[bool]。我想我看到了一个让我如此困惑的原因。我的循环仅显示列表中最后一个的文本节点。如果循环为所有其他元素显示一个文本节点,它可能会更明显。我要看看我能不能修好那个环。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=我想我看到了一个让我如此困惑的原因。我的循环仅显示列表中最后一个的文本节点。如果循环为所有其他元素显示一个文本节点,它可能会更明显。我要看看我能不能修好那个环。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=