我有一些简单的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
会返回 nil 。据我所知,这不应该发生。
奇怪的是,回到原始函数中的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文档中,我没有编写任何代码来插入它们。为什么他们在那里,为什么他们有车,我有什么办法可以阻止他们搞砸我的属性搜索?
答案 0 :(得分:7)
文本节点是解析器返回的空格
即<namespace:ChildNode name="right-name">
这些空白元素被视为<ParentNode>
答案 1 :(得分: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是否真的对您有用。
答案 2 :(得分:1)
#text节点是<namespace:ChildNode>
之前和之后的空白位。由于#text节点只是文本的一部分,因此它们没有属性。如果要删除这些节点,请尝试在XSL转换中使用xsl:strip-space,或者只检查该节点是否完全由空格组成。