ContentHandler 中的属性

在上一篇技巧文章的有关用 ContentHandler 进行数据处理的内容中,作者惟一没有讨论到的一个方面就是属性处理。虽然属性最常用于 XML 文档和 XML 处理程序之间的信息传输,但是它们通常也包含有用的业务数据。在本技巧文章中,Brett 为您展示了 SAX 是如何处理元素并报告这些元素的,以及如何用代码提取元素数据。

如果您一直在阅读本技巧系列,那么您可能以为会读到有关 SAX ErrorHandler 接口的内容 -- 我在上一篇技巧文章结束时是这样承诺的,当然我也是这么打算的。不过,我收到了一些请求和建议,让我讨论在前几篇技巧文章中一直讨论的 ContentHandler 接口的最后一个方面。由于这是一个不错的请求,而且还涉及 XML 处理的其他非常常见的内容,我想值得现在讨论它(对于只希望了解错误处理及类似内容的读者,我希望你们可以等到下一篇技巧文章!)。

当然,这项请求是针对 XML 属性处理的。读过最近几篇技巧文章后,我相信您对于安装、注册和使用 ContentHandler s 已经没有问题了,并且可以毫无问题地找到特定的元素或者得到其文本内容。不过,我没有提到如何获得一个属性的值。这是一个相当简单的过程,所以我会在本技巧中对它作一个简单的介绍。

首先,您需要找到要获取其值的这个属性(或者几个属性)。要完成这项任务,应该首先确定这个属性出现在哪个元素上。可以通过查看感兴趣的 XML 文档(清单1展示了一个简单的例子)、或者浏览一个 DTD (在清单2中展示)或者 XML Schema 做到这一点。它们都是有效的方法 -- 您可以选择一种自己喜欢的方法。

 

清单1. 一个简单的 XML 文档

<?xml version="1.0"?>
<root>
  <some-element some-attribute="value">Some content in the element</some-element>
  <some-other-element>
    <child age="1" birthDate="06/02/2003">
      More content
    <child>
  </some-other-element>
<root>
清单2. 一个简单的 XML DTD (用于清单1)
<!ELEMENT root (some-element*, some-other-element+)>
<!ELEMENT some-element (#PCDATA)>
<!ATTLIST some-element
          some-attribute	CDATA	#REQUIRED
>
<!ELEMENT some-other-element (child+)>
<ELEMENT child (#PCDATA)>
<!ATTLIST child
          age                   CDATA	#REQUIRED
          birthDate             CDATA	#REQUIRED
>
为了使用这个例子,这里假定要查找的是 birthDate 属性。不管查看的是 XML 文档还是 DTD(或者一个XML Schema),
都可以确定这个 birthDate 属性是附加在 child 元素上的。所以第一项任务是找出这个元素。当然,您已经知道如何去做了,
所以这是轻而易举的事情 -- 如果您忘了如何去做,那么可以参看清单3作为复习。
清单3. 找出子元素
public void startElement (String uri, String localName,
		       String qName, Attributes atts)	throws SAXException {
	
	    if (localName.equals("child")) {
		    // Deal with the attributes
	    }
}
 
现在,您要开始使用一个新的 SAX 类 Attributes 。确切地说,它实际上是一个接口,您的解析器提供商提供了这个接口的
一些类型的实现。不管使用哪种实现,您只需要处理公共接口方法,所以无需担心在外壳里面发生的事情。首先,看一下清单4,
它实质上就是 Attributes 接口。
 
清单4. SAX Attributes 接口 

package org.xml.sax;
public interface Attributes
{
   
    // Indexed access.
   
    public abstract int getLength ();
    public abstract String getURI (int index);
    public abstract String getLocalName (int index);
    public abstract String getQName (int index);
    public abstract String getType (int index);
    public abstract String getValue (int index);
   
    // Name-based queries
   
    public int getIndex (String uri, String localName);
    public int getIndex (String qName);
    public abstract String getType (String uri, String localName);
    public abstract String getType (String qName);
    public abstract String getValue (String uri, String localName);
    public abstract String getValue (String qName);
}

这是很容易理解的,本技巧的其余部分并没有什么启示性(revelatory)。正如本接口的注释所表明的,可以通过属性的名称或

者其索引访问它。如果您知道属性的名称(就像在这个虚构的例子一样 -- birthDate ),我建议使用基于名称的查询,如清单5所示。

清单5. 查找 birthDate 属性 
public void startElement (String uri, String localName,
     String qName, Attributes atts)throws SAXException { 
     if (localName.equals("child")) {
      String childValue = atts.getValue("", "birthDate");
   // Do something with the value
  }
}

很简单,是不是?注意我本来可以采用取 qName 中值的方式( getValue(String qName) ),但是为了自我文档编制(self-documentation)的方便,我一般喜欢传入一个 URI 和本地名称。这里没有 URI,所以使用一个空字符串就可以了。也可以使用 getValue("birthDate") 得到同样的结果。

您还可以用基于索引的访问方法来使用属性。如果知道属性的名称的话,一般不会使用这种方法。事实上,在这里它有明显的

危险性。SAX 规范不保证 XML 属性按照属性在被处理的文档中出现的顺序报告它们。这意味着,即使可以亲眼看到特定的属性出现在一个元素的属性列表中

的第二个位置,也不能保证在报告给 startElement() 方法的属性列表中它是第二个出现的属性。所以确实不应该对指定了名称的元素使用基于索引的访问方法。

然而,基于索引的访问仍然有实际用途。例如,它让您可以检查所有的属性,然后得到每一个属性的名称和值。考虑清单6中的

代码,它就是完成这项工作的,这里全部使用了基于索引的访问。

 

清单6. 检查子元素的所有属性

public void startElement (String uri, String localName,
		      String qName, Attributes atts)
  throws SAXException {
	
    if (localName.equals("child")) {
      int numAtts = atts.getLength();
        for (int i=0; i<numAtts; i++) {
          String attName = atts.getQName(index);
	      String value = atts.getValue(index);
	      System.out.println(" * Attribute named " + attName + 
	                  " found, with value '" + value + "'");
        }
    }
  }

好了,这次我真正讲完了 ContentHandler 接口。在下一篇技巧中,我将正式转入 ErrorHandler ,并分析究竟如何用它处理从错误放置的尖括号到缺少属性的各种事情。我还将为您展示一个解析器(由 XMLReader 的一个实例作为代表)如何可以注册多个处理程序。对于那些急于从本文中得到有关错误处理内容的读者,我要说一声抱歉!

在我的下一篇技巧文章中,我将再次在网上与您见面,把您的想法告诉我,正如您从本文可以看到的,读者的意见真的可以

起作用的。

注本原文见http://www.ibm.com/developerworks/cn/xml/x-tiphndl4/

参考:http://gceclub.sun.com.cn/Java_Docs/jdk6/docs/zh/api/org/xml/sax/package-tree.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值