2010-07-21 66 views
3

我有一个本应定位基于属性值的节点在传送一个子节点一些简单的处理XML代码:这些名为“#text”的XML节点发生了什么?

function GetNodeByAttributeValue(
    const AParentNode: IXMLNode; 
    const AttributeName: string; AttributeValue: Variant): IXMLNode; 
var 
    i: integer; 
    value: Variant; 
begin 
    result := nil; 
    if (not Assigned(AParentNode)) or (AttributeName = '') then 
    exit; 
    for i := 0 to AParentNode.ChildrenCount-1 do 
    begin 
    result := AParentNode.Children[i]; 
    value := result.GetAttributeValue(AttributeName, UnAssigned); 
    if not VarIsEmpty(value) then 
     exit; 
    end; 
    result := nil; 
end; 

非常简单的,对不对?但是,当我尝试运行此操作时,在某些情况下它会因访问冲突而崩溃。以下是发生了什么事情:

IXML *实现由RemObjects SDK库提供。 result.GetAttributeValue电话uROMSXMLImpl.TROMSXMLNode.GetAttributeValue,这就要求TROMSXMLNode.GetAttributeByName,它说

node := fNode.attributes.getNamedItem(anAttributeName); 

而这种崩溃是因为fNode.attributes回报。据我了解,这不应该发生。

奇怪的是,回到原始函数中的for循环,AParentNode.ChildrenCount返回3.但原始XML文档中的节点只有一个子节点。它符合我正在寻找的标准。

<ParentNode> 
    <namespace:ChildNode name="right-name"> 

AParentNode.ChildrenCount返回3.我在调试器中打开它们,并得到这个:

AParentNode.Children[0].name: '#text' 
AParentNode.Children[1].name: 'namespace:ChildNode' 
AParentNode.Children[2].name: '#text' 

在世界上什么是这些 “#text” 节点?它们不在XML文档中,我没有编写任何代码来插入它们。他们为什么在那里,为什么他们是越野车,有什么我可以做的,以防止他们搞砸我的属性搜索?

回答

7

文本节点是解析器返回的空白。
即压痕<namespace:ChildNode name="right-name">

这些空白元素之前被视为<ParentNode>

1

#text节点是<namespace:ChildNode>之前和之后的空白位。由于#text节点只是文本的一部分,所以它们没有属性。如果您想摆脱这些节点,请尝试在XSL转换中使用xsl:strip-space,或者只检查节点是否完全由空白组成。

2

孩子你有两个选择。您可以在解析器中设置一个选项以去除空格(禁用选项以保留空格) - 或者,您可以更好地检查您正在检查属性的节点是否实际上是元素,因为只有元素可以具有属性。这更好,因为如果XML具有这样的处理指令:<?some wired stuff?>,则即使对空白区进行条带化也没有帮助,因为在处理指令中查找属性也会在此解析器中提供AV。所以我添加到您的代码条件的NodeType这里:

function GetNodeByAttributeValue(
    const AParentNode: IXMLNode; 
    const AttributeName: string; AttributeValue: Variant): IXMLNode; 
var 
    i: integer; 
    value: Variant; 
begin 
    result := nil; 
    if (not Assigned(AParentNode)) or (AttributeName = '') then 
    exit; 
    for i := 0 to AParentNode.ChildrenCount-1 do 
    begin 
    result := AParentNode.Children[i]; 
    if result.NodeType = ntElement then 
    begin 
     value := Result.GetAttributeValue(AttributeName, UnAssigned); 
     if not VarIsEmpty(value) and (value = AttributeValue) then 
     exit; 
    end; 
    end; 
    result := nil; 
end; 

过滤你正在做的还可以在XSLT和/或XPath很容易做到,但我不知道这是否解析器支持XPath和不知道如果XSLT对你来说真的很方便。