65.9K
CodeProject 正在变化。 阅读更多。
Home

Flat DOM

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.46/5 (8投票s)

2005年10月24日

CPOL

2分钟阅读

viewsIcon

47317

downloadIcon

286

一种更简单的处理 XML 的方法。

引言

[注意 -- 以下概念和提供的代码也适用于 HTML。]

在处理 XML 文档时,通常有三种选择:

  1. 使用无状态事件驱动技术,例如 SAX。快速、高效,但非常底层。这种技术仅高于原始解析。
  2. 使用文档对象模型(DOM)方法。这种技术具有标准化的优势,但速度慢且占用大量内存。令人惊讶的是,将 XML 文档解析为分层数据结构并不像看起来那么有用,并且仍然需要做大量的工作才能做任何有用的事情。
  3. 使用 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 日:初始发布
© . All rights reserved.