我有一个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;
正确的方法是什么
编辑 当前状态(更正):如果我使用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标记,但这并不漂亮。
答案 0 :(得分:1)
CDATA节点与Text节点不同。您不能使用IXMLNode.Text
属性来读取CDATA节点的内容。这是documented behavior:
Text
供IsTextElement
属性为true的使用节点使用。如果IsTextElement
为false,则该节点没有子代,则该值为Text
中的一个是空字符串。设置
Text
是在这种情况下导致IsTextElement
为真的节点。如果节点具有子节点(单个DOM文本节点除外),则读取或设置
Text
会导致异常。
您需要改为使用IXMLNode.NodeValue
属性,该属性可以读取CDATA和文本内容:
ShowMessage(INode.NodeValue);