Что происходит с этими узлами 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 возвращает 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-документе, и я не писал никакого кода для их вставки. Почему они здесь, и почему они глючат, и могу ли я что-нибудь сделать, чтобы они не испортили мой поиск атрибутов?


person Mason Wheeler    schedule 21.07.2010    source источник


Ответы (3)


Текстовые узлы — это пробелы, возвращаемые синтаксическим анализатором.
т. е. отступ перед <namespace:ChildNode name="right-name">

Эти пробельные элементы рассматриваются как дочерние элементы <ParentNode>

person crowne    schedule 21.07.2010

У вас есть два варианта. Вы можете установить параметр в синтаксическом анализаторе для удаления пробелов (отключить параметр для сохранения пробелов) - или, что лучше, вы можете проверить, действительно ли узел, который вы проверяете на наличие атрибутов, является элементом, потому что только элементы могут иметь атрибуты. Это лучше еще и потому, что если 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 будет вам удобен.

person Community    schedule 22.07.2010

Узлы #text — это пробелы до и после <namespace:ChildNode>. Поскольку узлы #text — это просто фрагменты текста, у них нет атрибутов. Если вы хотите избавиться от этих узлов, попробуйте использовать xsl: strip-space в преобразовании XSL или просто проверьте, состоит ли узел полностью из пробелов.

person Michael Williamson    schedule 21.07.2010