Flat DOM






3.46/5 (8投票s)
一种更简单的处理 XML 的方法。
引言
[注意 -- 以下概念和提供的代码也适用于 HTML。]
在处理 XML 文档时,通常有三种选择:
- 使用无状态事件驱动技术,例如 SAX。快速、高效,但非常底层。这种技术仅高于原始解析。
- 使用文档对象模型(DOM)方法。这种技术具有标准化的优势,但速度慢且占用大量内存。令人惊讶的是,将 XML 文档解析为分层数据结构并不像看起来那么有用,并且仍然需要做大量的工作才能做任何有用的事情。
- 使用 XSLT 或 XPath 在标准 DOM 之上。这种技术通常被认为是最容易使用的,但效率最低。此外,许多类型的操作不适合这些高级模型,并且下降到较低级别的代码很困难。
我们提供第四种方法,其效率接近 SAX,并提供接近 XPath 的易用性,同时允许我们轻松地下降到较低的编程级别。我们称我们的解决方案为“扁平化 DOM”,原因很快就会变得明显。
非常简单地说,我们使用 SAX 构建一个键/值对列表。键是到该特定条目的完整路径。值是文本或属性的数量。我们使用特殊字符 @ 来表示属性,使用 #text 来表示文本段。连续的文本段为了便于处理而被合并在一起。下面的示例说明了我们的意思。
如果我们采用下面的 XML 文档示例...
<?xml version="1.0" encoding="UTF-8"?>
<content xmlns="http:XMLSerialization">
<object id="2">
<class flag="3" id="0" name="NSArray" suid="-3789592578296478260">
<field name="objects" type="java.lang.Object[]"/>
</class>
<array field="objects" id="4" ignoreEDB="1" length="3" type="java.lang.Object[]">
<string id="5">The Chestry Oak</string>
<string id="6">A Tree for Peter</string>
<string id="7">The White Stag</string>
</array>
</object>
</content>
... 并将其处理为扁平化 DOM,我们得到键/值对列表(表示为键:值)
/content/: #START#
/content/@xmlns: http:XMLSerialization
/content/object/: #START#
/content/object/@id: 2
/content/object/class/: #START#
/content/object/class/@flag: 3
/content/object/class/@id: 0
/content/object/class/@name: NSArray
/content/object/class/@suid: -3789592578296478260
/content/object/class/field/: #START#
/content/object/class/field/@name: objects
/content/object/class/field/@type: java.lang.Object[]
/content/object/class/field/: #END#
/content/object/class/: #END#
/content/object/array/: #START#
/content/object/array/@field: objects
/content/object/array/@id: 4
/content/object/array/@ignoreEDB: 1
/content/object/array/@length: 3
/content/object/array/@type: java.lang.Object[]
/content/object/array/string/: #START#
/content/object/array/string/@id: 5
/content/object/array/string/#text: The Chestry Oak
/content/object/array/string/: #END#
/content/object/array/string/: #START#
/content/object/array/string/@id: 6
/content/object/array/string/#text: A Tree for Peter
/content/object/array/string/: #END#
/content/object/array/string/: #START#
/content/object/array/string/@id: 7
/content/object/array/string/#text: The White Stag
/content/object/array/string/: #END#
/content/object/array/: #END#
/content/object/: #END#
/content/: #END#
遍历此列表并提取所需的数据现在相对容易。我们可以根据需要使用正则表达式或复杂的匹配标准。
我们选择采用接口和实现方法来表示结构的代码。原因是允许对列表结构的替代表示。例如,键部分有很多重复。我们编写了一个实现,将键部分单独存储,以便压缩内存中的表示。我们还编写了一个用于处理 HTML 的实现。还可以编写一个将数据存储和访问于文件或数据库中的实现。接口是
public interface XMLVector {
public int length();
public String getPath(int i);
public String getValue(int i);
public int[] getPosition(String key);
public int[] getPosition(Pattern keyRe);
public String getValue(String key);
public String getValue(Pattern keyRe);
}
以下是使用库提取 XML 文件中所有属性的示例
public class Main {
public static void main(String[] args) throws Throwable {
File f = new File("sample1.xml");
XMLVector vec = new XMLVectorImp(f);
System.out.println(vec);
// Extract all attributes for fun
int pos[] = vec.getPosition(Pattern.compile(".*@.*"));
for(int i = 0; i<pos.length; ++i) {
System.out.println(vec.getPath(pos[i])+": "+vec.getValue(pos[i]));
}
}
}
希望您会发现它像我一样有用且易于使用。代码是用 Java 编写的,但概念非常简单,将其翻译成 C# 和其他语言不应该太困难。
历史
- 2005 年 10 月 24 日:初始发布