2017-01-29 7 views
3

IDOMNodeとIXMLNodeの区別に苦労します。 ドキュメント内の子要素をXPathで選択したノードに追加したいとします。私が試した何DelphiはXPathの結果に子要素を追加します

努力1:私は

intfDocAccess : IXmlDocumentAccess; 
doc: TXMLDocument; 
... 
if Supports(N.OwnerDocument, IXmlDocumentAccess, intfDocAccess) then 
    doc := intfDocAccess.DocumentObject 
    else 
    doc := nil; 
    NodeAsIXMLNode := TXmlNode.Create(N, nil, doc); 

を使用してバックIXMLNodeにそれを変換する場合IDOMNodeSelect.selectNodes(expression); からIDOMNode ..:

私は、XPath結果ノードNを取得それに子供を追加すると、アクセス違反がスローされます。

直接XPathの結果ノードに子ノードを追加してください:

おそらくNodeAsIXMLNodeは...でも、元の文書には、それは型の互換性のために作成されたばかりのコピーだ

努力2ではありません

XMLNode := XmlDoc.CreateElement('tag', ''); 
N.appendChild(XMLNode as IDOMNode); 

スローインターフェイスがサポートされていません。私は、XPathの結果IDOMNodeノードも元のIXMLDocumentのメンバーではなく、ちょうど何らかの結果のコピーであると感じています。ちょうど推測。

xpathを使用してノードを選択してから、子要素ノードを追加するにはどうすればよいですか? オリジナルのIXMLDocumentが更新されます。

更新: は、XML文書全体のツリーを横断して動作していないにもXPathの結果DOMNodeをしてIXMLNodeのDOMNodeを比較 - XPathの結果ノードが、元のドキュメントに含まれていない、それが判明しました。試みMSXML、ADOM及びomnixml実装/ XE7/

アップデート2:ちょうど変換関数に

doc := _xpathdoc as TXMLDocument; // _xpathdoc : the IXMLDocument 

doc := nil; 

を交換する第一の方法で動作するように管理 、。

+0

XPathは、ドキュメントの操作ではなく、検索のみを目的としています。 XPathの 'IDOMNode'を元の' IXMLNode'に変換することはできません。また、 'selectNodes()'はDOMノードがどこにあるかを報告しません。一致するノードを探して文書を反復すると、XPathを使用する目的が無効になります。最初に手動で文書を反復し、XPathをまったく使用しないこともできます。 –

+0

ありがとう、多分、なぜそれがとても快適なときにxpathを使用しないのですか?もちろん、xpathの結果を無効にする方法で文書を操作することもできますが、そうではありません。現在動作している方法については、Update 2を参照してください。 – kgz

+0

'doc:= TXMLDocument(_xpathdoc);'は安全でない型キャストとみなされ、キャストに失敗した場合は 'nil'を返します。 "安全な"キャストは、代わりに 'as'演算子を使うことです。キャストが失敗した場合に例外を送出します:' doc:= _xpathdoc as TXMLDocument; ' EmbarcaderoのDocWikiの[オブジェクトへのインターフェイス参照のキャスト](http://docwiki.embarcadero.com/RADStudio/en/Interface_References#Casting_Interface_References_to_Objects)を参照してください。 –

答えて

0

私はこのことができますかどうかわからないんだけど、あなたはXMLドキュメントTMemoオブジェクトと/Content/Clientsを含むTEDIT、edPathQueryにロード

<Content> 
    <Clients> 
    <Client> 
     <ID value="88"/> 
     <Forename value="John"/> 
     <Surname value="Smith"/> 
    </Client> 
    </Clients> 
</Content> 

があるとします。その後、次のコードは、クライアントのノードを見つけ、それに

procedure TForm1.btnLoadClick(Sender: TObject); 
var 
    XmlDoc: IXMLDOMDocument; 
    NodeList : IXmlDOMNodeList; 
    Node, 
    NewNode : IXmlDomNode; 
    E : IXmlDomElement; 
    TextNode : IXMLDOMText; 
    Value : String; 
    I : Integer; 
begin 
    Memo2.Lines.Clear; 
    XmlDoc := CoDOMDocument.Create; //CreateOleObject('Microsoft.XMLDOM') as IXMLDOMDocument; 
    XmlDoc.Async := False; 
    XmlDoc.LoadXML(Memo1.Lines.Text); 
    if xmlDoc.parseError.errorCode <> 0 then 
    raise Exception.Create('XML Load error:' + xmlDoc.parseError.reason); 

    NodeList := XmlDoc.documentElement.SelectNodes(edPathQuery.Text); 

    if NodeList.length > 0 then begin 
    E := XMLDoc.createElement('Added'); 
    // E.nodeValue := 'Something'; Note the error this raises. Using the 
    // TextNode as below avoids this 
    NewNode := E as IXMLDomNode; 
    TextNode := XMLDoc.createTextNode('Data'); 
    NewNode.appendChild(TextNode); 
    NodeList.item[0].appendChild(NewNode); 
    end; 
    Memo2.Lines.Text := XMLDoc.documentElement.xml; 
end; 

を新しいノード+値を追加します。このコードはD7が付属していますMSXML.Pasインポートユニットを使用し、MSXML.DLLのバージョンで生成されましたこれは現在の時刻(C:\ WINDOWS \ SYSTEM \ MSXML.DLL)です。

個人的に、Delphiの「抽象化された」TXmlDocumentが役に立ちました。私はMSXMLのオブジェクトを使用する方が簡単だと分かりました。 Ymmv ...

関連する問題