服务器 频道

Oracle开发人员的 JDOM 和 XML 分析

  用XMLOutputter输出

  文档可以以多种不同的格式输出,但最常见的输出格式还是字节流。在JDOM中,XMLOutputter类提供这一能力。它的缺省无参数生成器试图忠实地输出一个与内存中贮存的完全一样的文档。下面的代码向一个文件生成一个文档的原始表示。

  // Raw output

  XMLOutputter outp = new XMLOutputter();

  outp.output(doc, fileStream);

  如果你不关心空格,那么你可以对文本块进行整理,以节省一点带宽:

  // Compressed output

  outp.setTextTrim(true);

  outp.output(doc, socketStream);

  如果希望文件打印得很漂亮,使其展示给人们看,则可以增加一些缩进空格,并增加一些新行:

  outp.setTextTrim(true);

  outp.setIndent(" ");

  outp.setNewlines(true);

  outp.output(doc, System.out);

  对于已有格式化空格的文档,要打印得很漂亮,就一定要进行整理。否则,就会在已经格式的文档上添加新的格式,使打印的文档显得很难看。

  定位元素树

  JDOM使得元素树的定位非常容易。为了取得根元素,可调用:

  Element root = doc.getRootElement();

  要得到它所有子元素的列表:

  List allChildren = root.getChildren();

  仅想得到具有给定名称的元素:

  List namedChildren = root.getChildren("name");

  仅想得到具有给定名称的第一个元素:

  Element child = root.getChild("name");

  getChildren()调用返回的列表是java.util.List,它是所有Java编程人员都知道的列表(List)接口的一个实现。这一列表令人感兴趣的地方在于它是活的。该列表的任何变化都会在支持的文档中立即反应出来。

  // Remove the fourth child

  allChildren.remove(3);

  // Remove children named "jack"

  allChildren.removeAll(root.getChildren("jack"));

  // Add a new child, at the tail or at the head

  allChildren.add(new Element("jane"));

  allChildren.add(0, new Element("jill"));

  利用该List隐喻(List metaphor)可以不必增加过多的方法而进行许多元素操作。但是为了方便起见,在结尾增加元素或者删去给定名字的元素之类的常用任务都有涉及到元素(Element)自身的方法,而不需要首先得到该List:

  root.removeChildren("jill");

  root.addContent(new Element("jenny"));

  采用JDOM的一个好处就是它可以很容易地在一个文档内或在文档之间移动元素。两种情况的代码相同,如下所示:

  Element movable = new Element("movable");

  parent1.addContent(movable);  // place

  parent1.removeContent(movable); // remove

  parent2.addContent(movable);  // add

  采用DOM时,移动元素就没有这么容易,因为在DOM中,元素是与它的生成工具紧紧联系在一起的。所以在文档之间移动DOM元素时,必须将其"导入"。

  而采用JDOM时,你需要记住的唯一一件事件就是在将一个元素增加到其他位置之前,需要先先将它删除,这样你就不会在树中形成循环。detach()方法可以用一行代码完成分离/增加:

  parent3.addContent(movable.detach());

  如果在将一个元素增加到另一个父元素之前忘了将它分离,则该库会产生一个异常(带有一个真正准确而有用的错误信息)。该库还会检查元素的名字和内容,以确保它们不包括空格之类的不恰当字符。它还会验证其他一些规则,如只有一个根元素、名称空间的声明是一致的、在注释和CDATA部分没有禁止使用的字符串等等。这一特性能够尽可能早地在该进程中进行"格式正确性"(well-formedness)错误检查。

  处理元素的属性

  元素属性的格式如下所示:

  <table width="100%" border="0"> ... </table>

  利用对元素的引用,可以要求元素的任意给定属性值:

  String val = table.getAttributeValue("width");

  也可以将属性看作一个对象,用于进行一些特殊的操作,如类型变换等:

  Attribute border = table.getAttribute("border");

  int size = border.getIntValue();

  要设置或改变一个属性,可以采用setAttribute():

  table.setAttribute("vspace", "0");

  要删除一个属性,可以采用removeAttribute():

  table.removeAttribute("vspace");

  处理元素文本内容

  一个文本内容类似于:

  <description>

  A cool demo

  </description>

  在JDOM中,这一文本可以通过调用直接获得:

  String desc = description.getText();

  要记住,因为XML 1.0规范要求保留空格,所以它会返回"\n A cool demo\n"。当然,有经验的编程人员常常不希望得到格式化的空格。有一个很方便的方法可以检索文本而同时忽略其中的空格:

  String betterDesc = description.getTextTrim();

  如果你真地希望去掉空格,那么有一个getTextNormalize()方法可以将内部空白成为一个标准空格。这一方法对于类似于下面这样的文本是非常方便的:

  <description>

  Sometimes you have text content with formatting

  space within the string.

  </description>

  要改变文本内容,可以应用setText()方法:

  description.setText("A new description");

  这一文本内的任何特殊字符都可以正确地被解释为一个字符,并根据需要在输出时删除,使以保持文本的语法正确。比如说你进行了这样一个调用:

  element.setText("<xml/> content");

  在内部存储中,仍然将这些字符串看作字符。不会对其内容进行隐式分析。在输出中,你将看到:

  <xml/> content<elt>

  这一操作保留了前面setText()调用的语义。如果你希望在一个元素中保留XML内容,则必须增加相应的JDOM子元素对象。

  处理CDATA节也可能在JDOM内进行。一个CDATA节指出不应被分析的文本块。它实质上是一个"语法糖块(syntactic sugar)",它允许很容易地包含HTML或XML内容,而不需要很多<和>换码字符。要建立一个CDATA节,只需要在CDATA对象内封装字符串即可:

  element.addContent(new CDATA("<xml/> content"));

  JDOM最了不起的地方是getText()调用返回字符串时,不会麻烦调用程序去判断它是否由CDATA节表示。

  处理混合内容

  一些元素包括有很多元素,如空格、注释、文本、子元素,以及其他元素:

  <table>

  <!-- Some comment -->

  Some text

  <tr>Some child element</tr>

  </table>

  如果一个元素中同时包含文本和子元素,就说它包含有"混合内容" 。处理混合内容可能是非常困难的,但JDOM使它变得非常容易。标准使用情况--返回文本内容和定位子元素--都非常简单:

  String text = table.getTextTrim(); // "Some text"

  Element tr = table.getChild("tr"); // A straight reference

  对于需要注释、空格块、处理指令和实体引用这样一些更复杂的应用来说,原始混合内容可以作为一个List(列表)来提供:

  List mixedCo = table.getContent();

  Iterator itr = mixedCo.iterator();

  while (itr.hasNext()) {

  Object o = i.next();

  if (o instanceof Comment) {

  ...

  }

  // Types include Comment, Element, CDATA, DocType,

  // ProcessingInstruction, EntityRef, and Text

  }

  就像子元素列表一样,对原始内容列表的改变会影响到支持的文档:

  // Remove the Comment. It''s "1" because "0" is a whitespace block.

  mixedCo.remove(1);

  如果你的观察力很强,则你会注意到这里有一个Text类。JDOM在内部采用Text类存储串内容,从而允许串具有"父辈(parentage)"关系,并更容易支持XPath访问。作为一个编程人员,在检索或设置文本时,不需要担心这种类,而只需要在访问原始内容列表时关心它就行了。.

  对于DocType、处理指令和EntityRef类的详细内容,请参见jdom.org上的API文档。

0
相关文章