我需要从XML文档中进行一些解析和信息检索。 XML文档绑定到XML数据绑定,然后针对特定元素进行解析。 一旦我隔离了我需要剖析的元素,我依次拿出每个元素(让我们称之为E_parent)并尝试在E_parent的整个XML文本中识别每个非文本子元素(E_child)的位置并进行一些操作或其他。
我遇到的问题是,XML文档的命名空间在单独访问时会添加到子元素的XML中。
举个例子,假设原始文件如下:
<?xml version="1.0" encoding="windows-1252"?>
<RootNode xml:lang="en" xmlns="urn:blah:names:blahblah">
<E_parent>Some text <E_child>child text</E_child> more parent text</E_parent>
</RootNode>
</xml>
当我尝试通过执行以下操作从E_parent或E_child元素访问XML时:
xmlParent := parentNode.XML;
我明白了:
<E_parent xmlns="urn:blah:names:blahblah">Some text <E_child>child text</E_child> more parent text</E_parent>
如果我尝试访问E_child的XML,我会得到:
<E_child xmlns="urn:blah:names:blahblah">child text</E_child>
当我尝试对父元素进行文本搜索时,这是一个问题,因为“真实”文本不包含该命名空间声明:
Some text <E_child>child text</E_child> more parent text
到目前为止,我已经通过在字符串中查找/删除不需要的命名空间属性来解决这个问题,但它效率很低,而且很丑陋; o) 所以,我的问题是,如何从绑定的XML文档中检索各种节点的XML,而不将文档命名空间添加到标记中?
======
感谢Remy,这是显而易见的,我只需要从空白字符串开始构建它而不是从内部XML开始!
请注意,这是一个比我针对这种特定情况更好的解决方法,但不是我想要的 - 获取没有命名空间的元素的XML仍然可用于其他事情,例如日志记录,其中我想要原始文档中显示的节点的确切XML。
答案 0 :(得分:1)
使用DOM处理E_parent的内容。而不是检索E_parent的XML
,然后在其中搜索E_child标签,使用DOM来确定E_child节点前面存在哪些纯文本(纯文本将有自己的子节点),并且该纯文本的长度将告诉您E_Child的确切文本位置,而无需根据E_parent的XML
进行检索。对于未标记文本的每个部分,E-parent将在相关位置具有多个纯文本子节点。
换句话说,鉴于您展示的XML,DOM的结构将如下所示:
RootNode
|
-- E_parent
|
|- "Some text "
|
|- E_child
| |
| -- "child text"
|
-- " more parent text"
答案 1 :(得分:1)
另一种方法是使用XPath来导航你的xml。
给出示例XML
<?xml version="1.0" encoding="windows-1252"?>
<RootNode xml:lang="en" xmlns="urn:blah:names:blahblah">
<E_parent>Some text <E_child>child text</E_child> more parent text</E_parent>
</RootNode>
您可以使用MSXML解析器直接使用一点XPath导航到您的E_child元素。首先,您需要制作自己的MSXML2_TLB单元副本。你可以使用看起来像这样的Delphi代码来访问E_child节点:
uses MSXMLDOM,MSXML2_TLB;
procedure Sample;
var
doc: IXMLDOMDocument2;
root: IXMLDomElement;
nodes: IXMLDOMNodeList;
node: IXMLDOMNode;
begin
doc := CoDOMDocument60.Create;
doc.async := false;
// Use same namespace as the default namespace here
doc.setProperty('SelectionNamespaces', 'xmlns:t="urn:blah:names:blahblah"');
doc.setProperty('SelectionLanguage', 'XPath');
doc.loadXML(XmlSource.Text);
root := doc.documentElement;
nodes := root.selectNodes('//t:E_child');
// Now thee nodes contains all E_child nodes
// Processs them here
// ...
end;
关键是您为XPath查询使用文档默认命名空间的特定前缀。 // t:E_child 是用于查找E_child元素的实际XPath表达式。
答案 2 :(得分:0)
使用您拥有的代码,然后使用Pos / PoxEx查找E_Child元素的开头和结尾。
var
cStart, cEnd: Integer;
ChildName, ChildText: string;
begin
... other code
xmlParent := parentNode.XML;
ChildName := 'E_Child';
// Find starting position of child tag
cStart := Pos('<' + E_Child, xmlParent);
// You now have the opening <
cEnd := PosEx('</' + E_Child, xmlParent, cStart);
// You now have the final < of the child.
// Add the length of the child's name + the closing >
Inc(cEnd, Length('</' + E_Child + '>'));
// Grab the entire child XML
ChildText := System.Copy(xmlParent, cStart, cEnd - cStart);
// Do whatever you want with the child. For instance,
// remove the original text.
System.Delete(xmlParent, cStart, cEnd - cStart);
// Replace it with new text
System.Insert(NewChildText, xmlParent, cStart);
end;
答案 3 :(得分:0)
基本上,除了XML解析器之外,您不能使用任何东西来解析XML。 RegEx won't work。任何比RegEx简单的东西都不会起作用。
在某些时候,您尝试解析的XML会发生变化,从而破坏您的简单搜索/替换代码。
您需要做的是在XML术语中定义应该由哪个替换,而不是在文本术语中。
您将最终定义应更改/插入/删除节点的内容。
然后你需要把它翻译成Delphi DOM代码。
可以帮助大量时间的东西,是一个XML工具(如XML Spy,但还有更多),它为您提供了XML的DOM树视图。
放置原始旧XML并将新XML更改为彼此。
从那里,您可以直观地看到旧树和新树,这将导致您记下所需的XML节点中的更改。
- 的Jeroen