6

次の形式の XML があります。

<Accounts>
   <Account Number="1"   DebitAmount="1000" Amount="2827561.95" /> 
   <Account Number="225" DebitAmount="2000"  Amount="12312.00" /> 
   <Account Number="236" DebitAmount="London"    Amount="457656.00" /> 
   <Account Number="225" DebitAmount="London"    Amount="23462.40" /> 
   <Account Number="236" DebitAmount="Bangalore" Amount="2345345.00" /> 
</Accounts>

Xpath を使用して一意のアカウント番号を取得するにはどうすればよいですか? つまり、値 1、225、および 236 を取得したいのです。

これは私がしたことです:(私はDelphi 2007を使用しています...)

Const XmlStr =
' <Accounts>
   <Account Number="1"   DebitAmount="1000" Amount="2827561.95" /> 
   <Account Number="225" DebitAmount="2000"  Amount="12312.00" /> 
   <Account Number="236" DebitAmount="London"    Amount="457656.00" /> 
   <Account Number="225" DebitAmount="London"    Amount="23462.40" /> 
   <Account Number="236" DebitAmount="Bangalore" Amount="2345345.00" /> 
</Accounts>';

 function GetAccountNumbers:TList;
 Var
   XMLDOMDocument  : IXMLDOMDocument;
   accounts : IXMLDOMNodeList;
  accountdetail :IXMLDOMNode;
   i:Integer
   list :TList
 begin
   Result:=TList.Create;
   XMLDOMDocument:=CoDOMDocument.Create;
   XMLDOMDocument.loadXML(XmlStr);
   accounts:= XMLDOMDocument.SelectNodes(''./Accounts 
  /Account[not(@Number=preceding-sibling/ Account /@Number)]');
  for i := 0 to accountdetails.length - 1 do begin
     accountdetail := accountdetails.item[i];
     //omitting the "<>nil" checks...
     list.Add(accountdetail.attributes.getNamedItem('Number').Nodevalue;
  end;
 end;

しかし、これはノードを返しません (accountdetails.length=0)。ここで何が欠けているか教えてください。

ありがとう、

プラディープ

4

5 に答える 5

5

Delphi 2007 のバージョンの MSXML は XPath 軸をサポートしていないようです。したがって、次のコードを使用することにした場合は、最初にMicrosoft XML, v3.0またはMicrosoft XML, v6.0タイプ ライブラリをインポートしてから、これを試してください。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MSXML2_TLB;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  XMLString =
    '<Accounts>' +
    '<Account Number="1" DebitAmount="1000" Amount="2827561.95"/>' +
    '<Account Number="225" DebitAmount="2000"  Amount="12312.00"/>' +
    '<Account Number="236" DebitAmount="London" Amount="457656.00"/>' +
    '<Account Number="225" DebitAmount="London" Amount="23462.40"/>' +
    '<Account Number="236" DebitAmount="Bangalore" Amount="2345345.00"/>' +
    '</Accounts>';

type
  TIntegerArray = array of Integer;

function GetAccountNumbers(const AXMLString: string): TIntegerArray;
var
  I: Integer;
  XMLDOMNodeList: IXMLDOMNodeList;
  XMLDOMDocument: IXMLDOMDocument3;
begin
  XMLDOMDocument := CoDOMDocument60.Create;
  if Assigned(XMLDOMDocument) and XMLDOMDocument.loadXML(AXMLString) then
  begin
    XMLDOMNodeList := XMLDOMDocument.selectNodes('/Accounts/Account[not(@Number=preceding-sibling::Account/@Number)]/@Number');
    SetLength(Result, XMLDOMNodeList.length);
    for I := 0 to XMLDOMNodeList.length - 1 do
      Result[I] := XMLDOMNodeList.item[I].nodeValue;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  I: Integer;
  IntegerArray: TIntegerArray;
begin
  S := 'Account numbers: ';
  IntegerArray := GetAccountNumbers(XMLString);
  for I := 0 to Length(IntegerArray) - 1 do
    S := S + IntToStr(IntegerArray[I]) + ', ';
  Delete(S, Length(S) - 1, 2);
  ShowMessage(S);
end;

end.
于 2012-06-05T10:16:23.567 に答える
1

何を達成したいのか正確に理解していない。多分これ?

'/Accounts/Account[not(@Number=preceding-sibling::node()/@Number)]/@Number'
于 2012-06-05T11:22:25.100 に答える
1

これは、Delphi XE2 の XPath の例で機能し、XPathの例をDelphi 2007 に更新すると、次の出力が得られます。

nodeName[0]:Number
nodeValue[0]:1
nodeName[1]:Number
nodeValue[1]:225
nodeName[2]:Number
nodeValue[2]:236

この例のアイデアは、MSXML 6 DOM または OpenXML DOM (Delphi XE2 は MSXML 6 DOM または ADOM XML v4 DOM をサポートしています) のいずれかを使用して、Delphi および 2007 を使用できるようにする必要があります。

MSXML 6 の動作は、Windows OS に依存するインストール済みの実際のバージョンに大きく依存することに注意してください (したがって、この回答)。

これはおそらく、最新の MS XML 6 がインストールされていないか、そこから適切なタイプ ライブラリがインポートされていないことを意味します (Delphi 2007 msxml ユニットには、XPath サポートに必要なIXMLDOMDocument2が含まれていません)。

2012 年 7 月 27 日、時間を作ってサンプルを Delphi 2007 にレトロフィットさせてテストしました。
完全にメモリ リークがないかどうかは完全にはわかりませんが (インターフェイスを配置するために TDictionary クラスをハックしました)、結果は Delphi XE2 の例と同じで、一見問題ないように見えます。

デモ アプリで、XPathTester例 3 を読み込み、XPath を実行します (例を読み込み、XPath を実行します)。

bo ライブラリの他のほとんどのものには、少なくとも Delphi 2009 が必要ですが、この部分は機能することに注意してください。
次の数週間で、まだ Delphi 2007 にある別のプロジェクトで必要に応じてテストします。

procedure TMainForm.LoadXmlExample3ButtonClick(Sender: TObject);
begin
  LoadXmlExample([ // unique account numbers
    '/Accounts/Account[not(@Number=preceding-sibling::Account/@Number)]/@Number'
  ], 
  [
    '<?xml version="1.0"?>',
    '<Accounts>',
    '  <Account Number="1"   DebitAmount="1000" Amount="2827561.95" />',
    '  <Account Number="225" DebitAmount="2000"  Amount="12312.00" />',
    '  <Account Number="236" DebitAmount="London"    Amount="457656.00" />',
    '  <Account Number="225" DebitAmount="London"    Amount="23462.40" />',
    '  <Account Number="236" DebitAmount="Bangalore" Amount="2345345.00" />',
    '</Accounts>'
  ]);
end;
于 2012-06-05T16:58:21.560 に答える
0

このコードを試してください:

XMLDocument1: TXMLDocument;

procedure TForm1.Button2Click(Sender: TObject);
var
  BodyNode:IXMLNode;
  I: Integer;
  sl:TStringList;
begin
  sl:=TStringList.Create;
  XMLDocument1.Active:=False;
  XMLDocument1.FileName:='C:\Zeina\Test.xml';
  XMLDocument1.Active:=True;

  BodyNode:=XMLDocument1.DocumentElement;
  for I:=0 to BodyNode.ChildNodes.Count-1 do
  begin
    if sl.IndexOf(BodyNode.ChildNodes[i].Attributes['Number'])=-1 then
      sl.Add(BodyNode.ChildNodes[i].Attributes['Number']);
  end;
  Memo1.Lines:=sl;
end;

これが結果です:

于 2012-06-05T09:04:40.723 に答える
-1

ジエナ、私はあなたのコードを変更します:

  XMLDocument1: TXMLDocument;

procedure TForm1.Button2Click(Sender: TObject);
var
  BodyNode:IXMLNode;
  I: Integer;
  sl:TStringList;
begin
  sl:=TStringList.Create;
  XMLDocument1.Active:=False;
  XMLDocument1.FileName:='C:\Zeina\Test.xml';
  XMLDocument1.Active:=True;

  BodyNode:=XMLDocument1.DocumentElement;
  sl.Duplicates := dupIgnore;
  for I:=0 to BodyNode.ChildNodes.Count-1 do
    sl.Add(
      BodyNode.ChildNodes[i].Attributes['Number']); // ignore duplicated lines  
   Memo1.Lines.AddStrings(sl); // for avoid memory leak
end;
于 2012-06-05T10:11:14.330 に答える