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 *の実装は、RemObjectsSDKライブラリによって提供されます。 result.GetAttributeValueを呼び出すuROMSXMLImpl.TROMSXMLNode.GetAttributeValue、を呼び出すTROMSXMLNode.GetAttributeByName、を言う

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

そして、 nilfNode.attributesを返すため、これはクラッシュします。私が理解しているように、それは決して起こらないはずです。

奇妙なことに、元の関数のforループにAParentNode.ChildrenCount戻ると、3が返されます。しかし、元のXMLドキュメントのノードには子ノードが1つしかありません。それは私が探している基準に一致します。

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

しかし、AParentNode.ChildrenCount3を返します。デバッガーでそれらを開き、これを取得します。

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

選択肢は 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 に答える