4

我有一些简单的 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 文档中,我也没有编写任何代码来插入它们。他们为什么在那里,为什么他们有问题,我能做些什么来防止他们搞砸我的属性搜索?

4

3 回答 3

8

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

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

于 2010-07-21T19:08:52.110 回答
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 是否真的对您有用。

于 2010-07-22T01:56:52.963 回答
1

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

于 2010-07-21T19:08:40.050 回答