如何使用IXMLNode从XML返回CDATA内容(delphi异常)

时间:2019-03-28 22:04:48

标签: delphi

我有一个XML文档,我尝试使用Delphi和XMLDoc提取值。大多数零件都可以正常工作。我使用IXMLNode选择节点文本。但是我有一节可能包含CDATA。当我尝试获取它时,总是会抛出异常。

我的XML(相关部分)与此类似

    <a>valuea</a>
    <b>My b value</b>
    <c>![CDATA[My cdata text goes here
It may have linefeed inside
like this
and I need to get all lines WITH linefeeds
]]>
</c>

我今天的代码是这样的:

  var
     IDoc: IXMLDocument;
     INode: IXMLNode;
     XPathText : string;
     i         : integer;

              // From a post in Embarcadero's Delphi XML forum.
              function selectNode(xnRoot: IXmlNode; const nodePath: WideString): IXmlNode;
              var
                intfSelect : IDomNodeSelect;
                dnResult : IDomNode;
                intfDocAccess : IXmlDocumentAccess;
                doc: TXmlDocument;
              begin
                Result := nil;
                if not Assigned(xnRoot) or not Supports(xnRoot.DOMNode, IDomNodeSelect, intfSelect) then
                  Exit;
                dnResult := intfSelect.selectNode(nodePath);

                if Assigned(dnResult) then
                begin
                  if Supports(xnRoot.OwnerDocument, IXmlDocumentAccess, intfDocAccess) then
                    doc := intfDocAccess.DocumentObject
                  else
                    doc := nil;
                  Result := TXmlNode.Create(dnResult, nil, doc);
                end;
              end;
// --------------------------------------------
   begin
       IDoc:= LoadXMLDocument(edtXMLFileName.Text);
       idoc.ParseOptions := [poPreserveWhiteSpace];
       XPathText := './/path/to/c';   // as per example above, this is my CDATA

        INode := selectnode(IDoc.DocumentElement, xpathtext);

        showmessage(inode.text);  // <<< Notice: .text not .XML FAILS for XML with exception.


   end;

正确的方法是什么

  • 获取CDATA值
  • ..同时保留任何换行符
  • 我不需要标签或CDATA标签。只是满足。

编辑 当前状态(更正):如果我使用IXMLNode的.XML值,则会得到完整的标签,包括CDATA等:

    <c>![CDATA[My cdata text goes here
It may have linefeed inside
like this
and I need to get all lines WITH linefeeds
]]>
</c>

但是如果我使用.text,则delphi会引发异常。

"Element does not contain a single text node."

有人建议here使用XMLTextReader,但是我需要在这里和那里查询,并且不能做正向只读操作。

我的备份计划是使用一个单独的函数来删除上面返回的XML / CDATA标记,但这并不漂亮。

1 个答案:

答案 0 :(得分:1)

CDATA节点与Text节点不同。您不能使用IXMLNode.Text属性来读取CDATA节点的内容。这是documented behavior

  

TextIsTextElement属性为true的使用节点使用。如果IsTextElement为false,则该节点没有子代,则该值为Text中的一个是空字符串。

     

设置Text是在这种情况下导致IsTextElement为真的节点。

     

如果节点具有子节点(单个DOM文本节点除外),则读取或设置Text会导致异常。

您需要改为使用IXMLNode.NodeValue属性,该属性可以读取CDATA和文本内容:

ShowMessage(INode.NodeValue);