新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论DOM, SAX, XPath等。
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 DOM/SAX/XPath 』 → SAX教程系列四(事件处理程序和SAX事件)----来源:IBM developerWorks 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 8966 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: SAX教程系列四(事件处理程序和SAX事件)----来源:IBM developerWorks 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     yuji1998 帅哥哟,离线,有人找我吗?魔羯座1981-12-22
      
      
      威望:5
      头衔:蓝色先锋
      等级:大二(研究C++)
      文章:212
      积分:1059
      门派:XML.ORG.CN
      注册:2004/4/10

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给yuji1998发送一个短消息 把yuji1998加入好友 查看yuji1998的个人资料 搜索yuji1998在『 DOM/SAX/XPath 』的所有贴子 访问yuji1998的主页 引用回复这个贴子 回复这个贴子 查看yuji1998的博客楼主
    发贴心情 SAX教程系列四(事件处理程序和SAX事件)----来源:IBM developerWorks

    欢迎您通过电子邮件nicholas@nicholaschase.com直接与作者 Nicholas Chase 联系。
    注:本教程仅供本站成员的学习和研究使用,严禁用于商业目的!

    startDocument()
         现在已经设置好了要解析的文档,下面可以开始使用在处理程序接收到适当的事件时实际做某件事情的反法,替换作为 DefaultHandler 的组成部分的默认实现。
    首先使用 startDocument() 事件来开始文档,但是不做任何事情。这个事件像其他 SAX 事件一样,会抛出一个 SAXException:
    ...

    import org.xml.sax.SAXException;

    public class SurveyReader extends DefaultHandler
    {

       public SurveyReader() {
       }

       public void startDocument() throws SAXException {
          System.out.println("Tallying survey results...");   
       }

       public static void main (String args[]) {
       
          XMLReader xmlReader = null;
        
          startElement()
         现在开始查看实际的数据。对于每个元素,这个例子都回显传递给 startElement() 事件的名称(参见下面的“元素清单”屏幕快照)。
    解析器实际上传递每个元素的多个信息:
    • 限定名称,或 qName。 这实际上是名称空间信息(如果有的话)和元素的实际名称的组合。如果有的话,qName 还包括冒号(:) —— 例如, revised:response。
    • 名称空间 URI。正如在名称空间中所讨论的,实际的名称空间是某种形式的 URI,而不是被添加到元素或属性名称的别名。例如,http://www.nicholaschase.com/surveys/revised/ 而不是简单的 revised:。
    • 本地名称。这是元素的实际名称,比如 question。如果文档没有提供名称空间信息,解析器也许不能确定 qName 的哪个部分是 localName。
    • 任何属性。元素的属性实际上是作为对象的集合来传递的,正如从下一小节中可以看到的那样。
    首先列出每个元素的名称:
    ...
    public void startElement(String namespaceURI, String localName,
                             String qName, Attributes atts) throws SAXException {

        System.out.print("Start element: ");
        System.out.println(qName);
       
        for (int att = 0; att < atts.getLength(); att++) {
           String attName = atts.getQName(att);
           System.out.println("   " + attName + ": " + atts.getValue(attName));   
       }

    }

       
         startElement():检索属性
         startElement() 事件还提供对元素属性的访问。这些属性在一个 Attributes 数据结构中传入。
    您可以基于它在数组中的位置或基于属性的名称检索一个属性值。
    ...
    public void startElement(String namespaceURI, String localName,
                             String qName, Attributes atts) throws SAXException {

        System.out.print("Start element: ");
        System.out.println(qName);
       
        for (int att = 0; att < atts.getLength(); att++) {
           String attName = atts.getQName(att);
           System.out.println("   " + attName + ": " + atts.getValue(attName));   
       }

    }
    ...   

         endElement()
         您会找到很多关注元素结尾的很好理由。例如,它可能是处理元素内容的一个信号。这里您将使用它来在某种程度上完美地打印文档,同时缩进每一层元素。基本的思路是在新元素开始时增加缩进的值,在元素结束时减小缩进的值:
    ...

    int indent = 0;

    public void startDocument() throws SAXException {
       System.out.println("Tallying survey results...");   

       indent = -4;
    }

       
    public void printIndent(int indentSize) {
       for (int s = 0; s < indentSize; s++) {
          System.out.print(" ");
       }
    }
       

    public void startElement(String namespaceURI, String localName,
                 String qName, Attributes atts) throws SAXException {
       
       indent = indent + 4;
       printIndent(indent);
        
       System.out.print("Start element: ");
       System.out.println(qName);
        
       for (int att = 0; att < atts.getLength(); att++) {

          printIndent(indent + 4);

          String attName = atts.getLocalName(att);
          System.out.println("   " + attName + ": " + atts.getValue(attName));   
       }
    }

    public void endElement(String namespaceURI, String localName, String qName)
       throws SAXException {
        
       printIndent(indent);
       System.out.println("End Element: "+localName);
       indent = indent - 4;   
    }

    ...
         characters()
         现在您已经获得了元素,下面可以继续使用 characters() 来检索实际的数据。这里花一会儿功夫查看一下这个方法的签名:
    public void characters(char[] ch,
                           int start,
                           int length)
                           throws SAXException
    注意在这个方法中,没有任何地方有任何信息表明这些字符属于哪个元素。如果您需要这个信息,就必须存储它。本例添加几个变量来存储当前元素和问题信息。(它还删除了所显示的大量无关信息。)
    这里请注意两个重要的事项:
    • 范围: characters() 事件不仅包括不仅一个字符串。它还包括起始和长度信息。实际上,ch 字符数组包括整个文档。应用程序一定不能尝试读取馈送给 characters() 事件的范围之外的字符。
    • 频率:SAX 规范没有要求处理器以任何特定方式返回字符,因此在多个部分中返回单个文本块是可能的。在假设您有某个元素的所有内容之前,始终要确保endElement()事件已经发生。而且,处理器可能使用ignorableWhitespace()来返回某个元素内的空白。对验证解析器而言就总是这种情况。
    ...
    public void printIndent(int indentSize) {
       for (int s = 0; s < indentSize; s++) {
          System.out.print(" ");
       }
    }
       
    String thisQuestion = "";
    String thisElement = "";

    public void startElement(String namespaceURI, String localName,
                    String qName, Attributes atts) throws SAXException {

       if (qName == "response") {
          System.out.println("User: " + atts.getValue("username"));
       } else if (qName == "question") {
          thisQuestion = atts.getValue("subject");
       }
       
       thisElement = qName;
       
    }

    public void endElement(String namespaceURI, String localName, String qName)
                                                            throws SAXException {

       thisQuestion = "";
       thisElement = "";
       
    }

    public void characters(char[] ch, int start, int length)
                                                 throws SAXException  {
     
       if (thisElement == "question") {
          printIndent(4);
          System.out.print(thisQuestion + ": ");
          System.out.println(new String(ch, start, length));
       }
    }


         记录答案 

    现在您已经获得了数据,下面可以继续添加实际的记录。
    这就像在完成调查时构造一个字符串来进行分析一样简单。
    ...

    String appearance = null;
    String communication = null;
    String ship = null;
    String inside = null;
    String implant = null;

    public void characters(char[] ch,
                           int start,
                           int length)
                           throws SAXException  {
     
       if (thisElement == "question") {


          if (thisQuestion.equals("appearance")) {
             appearance = appearance + new String(ch, start, length);
          }
          if (thisQuestion.equals("communication")) {
             communication = communication + new String(ch, start, length);
          }
          if (thisQuestion.equals("ship")) {
             ship = ship + new String(ch, start, length);
          }
          if (thisQuestion.equals("inside")) {
             inside = inside + new String(ch, start, length);
          }
          if (thisQuestion.equals("implant")) {
             implant = implant  + new String(ch, start, length);
          }


       }
    }
    ...
    务必记住,您能够在 characters() 方法中执行这个任务的唯一原因,是因为您要寻找的回答仅有一个字符长度。 如果您要寻在的内容具有任意长度,就必须把从每次调用中获得的数据收集起来,然后在元素的末尾用 endElement() 方法来分析它。

         ignorableWhitespace() 

    人工编制(而不是程序产生)的 XML 文档通常包括附加的空白,以使文档更易于阅读。空白包括换行、制表符和空格。 在大多数情况下,这种空白是无关的,应该在处理数据时忽略。
    所有验证解析器以及某些非验证解析器不是在 characters() 中将这些空白字符传递给内容处理程序,而是在 ignorableWhitespace() 事件中传递的。这样很方便,因为这样您就可以仅集中在实际的数据上。
    但是如果您确实 需要 空白,那该怎么办呢?在这样的场景中,您可以设置元素上的一个属性,以指示处理器不要忽略空白字符。这个属性就是 xml:space,它通常被假定为 default。(这意味着除非处理器的默认行为是保留空白,否则空白将被忽略。)
    为了告诉处理器 不要 忽略空白,可见这个值设置为 preserve,就象下面这样:
    <code-snippet xml:space="preserve">
       <line>public void endElement(</line>
                    <line>String namespaceURI,</line>
                    <line>String localName,</line>
                    <line>String qName)</line>
                        <line>throws SAXException</line>
    </code-snippet>
    endDocument() 第 8 页(共10 页)

    当然,一旦完成文档的解析,您将需要打印出最终记录,如下所示。
    这也是组合处理期间可能出现的任何零碎信息的很好机会。
    ...
          if (thisQuestion.equals("implant")) {
             implant = implant + new String(ch, start, length);
          }
       }
    }
       

    public int getInstances (String all,
                                String choice) {
       ...
       return total;
    }
       
    public void endDocument() {
     
       System.out.println("Appearance of the aliens:");
       System.out.println("A: " + getInstances(appearance, "A"));
       System.out.println("B: " + getInstances(appearance, "B"));
       ...
    }

             
       public static void main (String args[]) {
    ...
    processingInstruction() 第 9 页(共10 页)

    所有这一切都令人满意,但有时您可能希望直接包括处理数据的应用程序的信息。一个很好的例子就是您希望使用样式表来处理文档,比如:

    <?xml version="1.0" encoding="UTF-8"?>

    <?xml-stylesheet href="survey.xsl" version="1.0" type="text/xsl" ?>

    <surveys>
    ...

    其他应用程序能够以类似的方法获取信息。例如,调查的统计采样无疑没有足够大到适合严肃考虑的地步。您可以仅为应用程序添加处理指令,从而指定一个因子来放大被调查者的反应:

    <?xml version="1.0" encoding="UTF-8"?>

    <?SurveyReader factor="2" ?>

    <surveys>
    ...

    这可以由 processingInstruction() 事件获取,然后将它划分为 target 和data:

    ...
    public void processingInstruction(String target, String data)
          throws SAXException {
     
       System.out.println("Target = ("+target+")");
       System.out.println("Data = ("+data+")");
    }
    ...

         ErrorHandler 事件
         就像 ContentHandler 具有预定义用于处理内容的事件一样,ErrorHandler 也有预定义用于处理错误的事件。由于已指定了 SurveyReader 作为错误处理程序以及内容处理程序,您需要改写那些方法的默认实现。
    你需要关心三个事件:warning、error 和 fatalError:
    ...

    import org.xml.sax.SAXParseException;

    public class SurveyReader
                     extends DefaultHandler
    {

       public SurveyReader() {
       }
       
       public void error (SAXParseException e) {
          System.out.println("Error parsing the file: "+e.getMessage());
       }

       public void warning (SAXParseException e) {
          System.out.println("Problem parsing the file: "+e.getMessage());
       }

       public void fatalError (SAXParseException e) {
          System.out.println("Error parsing the file: "+e.getMessage());
          System.out.println("Cannot continue.");
          System.exit(1);
       }


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    私人网站:蓝尚WEB商务平台http://www.lanshang.com     建站黄页:http://www.lanshang.com/link.asp WEB技术文库:http://www.lanshang.com/wenzhang/ 
    电子书籍: http://www.lanshang.com/ebook/  技术交流:http://www.lanshang.com/bbs/

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2004/5/31 0:23:00
     
     GoogleAdSense魔羯座1981-12-22
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 DOM/SAX/XPath 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/19 7:59:58

    本主题贴数3,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  SAX教程系列四(事件处理程序和SAX事件)----来源:IBM developerWo..(10633字) - yuji1998,2004年5月31日
        回复:  IBM的这个教程在哪?能不能给出URL?thanks(40字) - tatezhou,2005年6月4日
        回复:  不好意思 打搅了 我是一名XML的初学者 正在看IBM的这个教程 但是我发现这个教程有些地..(2238字) - javaanselm,2004年7月18日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    85.938ms