android 自学日记(六) ——SAX解析中换行问题解决

今天在写一个小项目的时候用到了SAX解析,遇到了一点小问题,网上找了好久都没有解决,最后还是自己发现了解决方法,特地和大家分享一下!

问题描述:

先来看下要解析XML文件:

<dict num="219" id="219" name="219"><key>big</key><ps>bɪg</ps><pron>http://res.iciba.com/resource/amp3/oxford/0/dd/3e/dd3eded85f7085dc92210aa496e92ba9.mp3</pron><ps>bɪɡ</ps><pron>http://res.iciba.com/resource/amp3/1/0/d8/61/d861877da56b8b4ceb35c8cbfdf65bb4.mp3</pron><pos>adj.</pos><acceptation>大的;重要的;(计划)庞大的;大方的;
</acceptation><pos>adv.</pos><acceptation>大量地;成功地;夸大地;宽宏大量地;
</acceptation><pos>n.</pos><acceptation>大亨;大公司;
</acceptation><sent><orig>
The word " big " has one syllable and the word " Africa " has three syllables.
</orig><trans>
“ big ” 这个词只有一个音节而 “ Africa ” 有三个音节.
</trans></sent><sent><orig>
There remains a tension at the heart of BIG s predicament.
</orig><trans>
目前,BIG心里仍维持着一种紧张的态势.
</trans></sent><sent><orig>
BIG might sell its Bsian arm to another insurance firm; Prudential was not the only bidder.
</orig><trans>
BIG也许会将其亚洲分支出售给另外一家保险公司, 保信并不是独一的竞价人.
</trans></sent><sent><orig>
Carrie fell for the wealthy Mr. Big.
</orig><trans>
Carrie爱上了那位富有的Big先生.
</trans></sent><sent><orig>
In this sentence, the word BIG is in capitals.
</orig><trans>
本句中BIG一词用的是大写字母.
</trans></sent></dict>

大家都知道SAX解析的关键就是setContentHandler()方法中传入的DefaultHandler的子类,一开始我是这样写的:

public class WordsHandler extends DefaultHandler {
    //记录当前节点
    private String nodeName;
    private Words words;
    //单词的词性与词义
    private StringBuilder posAcceptation;
    //例句
    private StringBuilder sent;

    /**获取解析后的words对象*/
    public Words getWords() {
        return words;
    }

    //开始解析XML时调用
    @Override
    public void startDocument() throws SAXException {
        //初始化
        words = new Words();
        posAcceptation = new StringBuilder();
        sent = new StringBuilder();
    }

    //结束解析XML时调用
    @Override
    public void endDocument() throws SAXException {
        //将所有解析出来的内容赋予words
        words.setPosAcceptation(posAcceptation.toString().trim());
        words.setSent(sent.toString().trim());
    }

    //开始解析节点时调用
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        nodeName = localName;
    }

    //结束解析节点时调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

    }

    //获取节点中内容时调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String a = new String(ch, start, length);
        //去掉文本中原有的换行
        for (int i = start; i < start + length; i++) {
            if (ch[i] == '\n')
                return;
        }
        //将节点的内容存入Words对象对应的属性中
        if ("key".equals(nodeName)) {
            words.setKey(a);
        } else if ("ps".equals(nodeName)) {
            if (words.getPsE().length() <= 0) {
                words.setPsE(a);
            } else {
                words.setPsA(a);
            }
        } else if ("pron".equals(nodeName)) {
            if (words.getPronE().length() <= 0) {
                words.setPronE(a);
            } else {
                words.setPronA(a);
            }
        } else if ("pos".equals(nodeName)) {
            posAcceptation.append(a);
        } else if ("acceptation".equals(nodeName)) {
            posAcceptation.append(a);
             posAcceptation.append("\n");//重新排版换行
        } else if ("orig".equals(nodeName)) {
            sent.append(a);
            sent.append("\n");
        } else if ("trans".equals(nodeName)) {
            sent.append(a);
            sent.append("\n");
        } else if ("fy".equals(nodeName)) {
            words.setFy(a);
            words.setIsChinese(true);
        }
    }
}

这样的代码基本没什么问题,运行一下,大部分情况都能按照想要结果返回。
但是那,如果解析的字段中出现了“‘ < >这样的特殊符号时,就会发生问题 ,例如这句:

The word " big " has one syllable and the word " Africa " has three syllables.

运行后会发现解析结果是这样的:

The word 
" 
big 
" 
has one syllable and the word
" 
Africa
" 
has three syllables.

和想要的结果不一样,于是我找了好多资料,终于在理解的情况下解决了。

解决方法:

characters()方法在解析的时候会不停地调用,每次读取都是以 ’ ” < > 等这些字段为节点,上述情况就是因为characters()方法一次只读到文本中 ” 位置,并没有读完整个节点,因此添加了换行,而后再次调用characters()方法,读取的是“之后的内容,还是在这个节点中。正是这种同一个节点中不同地调用characters()方法,导致产生很多不需要的换行。

修改WordsHandler:

public class WordsHandler extends DefaultHandler {
    //记录当前节点
    private String nodeName;
    private Words words;
    //单词的词性与词义
    private StringBuilder posAcceptation;
    //例句
    private StringBuilder sent;

    /**获取解析后的words对象*/
    public Words getWords() {
        return words;
    }

    //开始解析XML时调用
    @Override
    public void startDocument() throws SAXException {
        //初始化
        words = new Words();
        posAcceptation = new StringBuilder();
        sent = new StringBuilder();
    }

    //结束解析XML时调用
    @Override
    public void endDocument() throws SAXException {
        //将所有解析出来的内容赋予words
        words.setPosAcceptation(posAcceptation.toString().trim());
        words.setSent(sent.toString().trim());
    }

    //开始解析节点时调用
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        nodeName = localName;
    }

    //结束解析节点时调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //在读完整个节点后换行
        if("acceptation".equals(localName)){
            posAcceptation.append("\n");
        }else if("orig".equals(localName)){
            sent.append("\n");
        }else if("trans".equals(localName)){
            sent.append("\n");
            sent.append("\n");
        }
    }

    //获取节点中内容时调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String a = new String(ch, start, length);
        //去掉文本中原有的换行
        for (int i = start; i < start + length; i++) {
            if (ch[i] == '\n')
                return;
        }
        //将节点的内容存入Words对象对应的属性中
        if ("key".equals(nodeName)) {
            words.setKey(a);
        } else if ("ps".equals(nodeName)) {
            if (words.getPsE().length() <= 0) {
                words.setPsE(a);
            } else {
                words.setPsA(a);
            }
        } else if ("pron".equals(nodeName)) {
            if (words.getPronE().length() <= 0) {
                words.setPronE(a);
            } else {
                words.setPronA(a);
            }
        } else if ("pos".equals(nodeName)) {
            posAcceptation.append(a);
        } else if ("acceptation".equals(nodeName)) {
            posAcceptation.append(a);
        } else if ("orig".equals(nodeName)) {
            sent.append(a);
        } else if ("trans".equals(nodeName)) {
            sent.append(a);
        } else if ("fy".equals(nodeName)) {
            words.setFy(a);
            words.setIsChinese(true);
        }
    }
}

仅仅是把重新排版的过程放到了endElement()方法执行,此方法是在节点结束时调用,即读到 </xxx> 这个标志时, 在这个方法中添加我们想要的换行就可以了。
上述讲到的那句:The word ” big ” has one syllable and the word ” Africa ” has three syllables.是在一个<org> </org> 中的,因此也只会在读取到 </org> 后才换行,达到我们想要的换行方式。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio ,可以使用 SAX 解析解析 XML 文件。SAX 解析器是一种基于事件的解析器,它可以将 XML 文件解析为一系列事件,然后通过监听这些事件来获取所需的数据。 以下是使用 SAX 解析解析 XML 文件的示例代码: ```java public class MyHandler extends DefaultHandler { private String currentValue; private boolean parsingName; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals("name")) { parsingName = true; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (parsingName) { // 处理姓名数据 parsingName = false; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (parsingName) { currentValue = new String(ch, start, length); } } } // 在 Activity 使用 SAX 解析器 try { InputStream inputStream = getResources().openRawResource(R.raw.my_xml_file); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); MyHandler handler = new MyHandler(); saxParser.parse(inputStream, handler); } catch (Exception e) { e.printStackTrace(); } ``` 在上面的示例代码,MyHandler 类继承了 DefaultHandler 类,并重写了 startElement()、endElement() 和 characters() 方法来监听 XML 文件的事件。在 startElement() 方法,可以判断当前解析的标签是否是所需的标签,并进行相应的处理;在 endElement() 方法,可以完成对标签数据的处理;在 characters() 方法,可以获取标签文本内容。 在 Activity ,可以使用 SAXParserFactory 类和 SAXParser 类来创建和使用 SAX 解析器。在调用 saxParser.parse() 方法时,需要传入要解析XML 文件的输入流和事件处理器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值