SAX Parser如何仅读取Item标签内的内容?
如何用SAX Parser忽略Channel标签,仅读取Item下的内容
我看了你更新后的代码,确实存在几个SAX解析里容易踩的坑,导致你无法正确捕获item内的title内容。先帮你梳理下问题,再给出修正后的完整方案。
你的代码存在的核心问题:
- 栈的初始化逻辑错误:你在每次遇到
item标签时都新建一个栈,这会直接覆盖之前的栈状态,导致后续的元素判断完全失效。 - 元素匹配逻辑不严谨:你混用了
localName和qName,而你的XML没有命名空间,localName大概率是空值,根本匹配不到item;另外link和author的判断也没有检查是否处于item内部。 - characters方法的使用误区:SAX的
characters方法会被多次调用(比如遇到换行、空格或者长文本拆分时),你直接在里面处理内容会丢失部分数据,而且在元素未结束时就输出,也不符合解析流程。 - 栈的弹出逻辑不安全:不管当前元素是什么都直接
pop,很容易导致栈空时抛出空指针异常。
修正后的完整代码
public void parse(InputSource is, AppDataBean appDataBean) throws RuntimeException { try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); Log.d("SAX", appDataBean.getUrl()); // 用栈跟踪当前解析的元素层级,也可以只用isInItem标记,两者结合更稳妥 Stack<String> elementStack = new Stack<>(); // 临时存储当前元素的文本内容,解决characters多次调用的问题 StringBuilder currentContent = new StringBuilder(); DefaultHandler handler = new DefaultHandler() { // 标记当前是否处于item标签内部 boolean isInItem = false; boolean captureTitle = false; boolean captureLink = false; boolean captureAuthor = false; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 将当前元素压入栈,记录层级 elementStack.push(qName); // 进入item标签时,标记状态 if (qName.equalsIgnoreCase("item")) { isInItem = true; } // 只有在item内部时,才开启对应元素的捕获 if (isInItem) { if (qName.equalsIgnoreCase(TITLE)) { captureTitle = true; currentContent.setLength(0); // 重置内容容器 } if (qName.equalsIgnoreCase(LINK)) { captureLink = true; currentContent.setLength(0); } if (qName.equalsIgnoreCase(AUTHOR)) { captureAuthor = true; currentContent.setLength(0); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // 只有在item内部,且当前元素是我们要捕获的时,才输出内容 if (isInItem) { if (qName.equalsIgnoreCase(TITLE)) { Log.d("SAX", "Item Title : " + currentContent.toString().trim()); captureTitle = false; } if (qName.equalsIgnoreCase(LINK)) { Log.d("SAX", "Item Link : " + currentContent.toString().trim()); captureLink = false; } if (qName.equalsIgnoreCase(AUTHOR)) { Log.d("SAX", "Item Author : " + currentContent.toString().trim()); captureAuthor = false; } } // 离开item标签时,重置状态 if (qName.equalsIgnoreCase("item")) { isInItem = false; } // 安全弹出栈顶元素,避免空指针 if (!elementStack.isEmpty()) { elementStack.pop(); } } @Override public void characters(char ch[], int start, int length) throws SAXException { // 只有在捕获状态开启时,才拼接文本内容 if (captureTitle || captureLink || captureAuthor) { currentContent.append(new String(ch, start, length)); } } }; saxParser.parse(is, handler); } catch (Exception e) { e.printStackTrace(); } }
关键改进点说明:
- 用
isInItem标记简化层级判断:相比直接操作栈,这个标记更直观,能快速判断当前是否处于item标签内部,避免栈操作的失误。 - StringBuilder存储文本:彻底解决
characters方法多次调用导致的内容截断问题,确保能获取到完整的元素文本。 - 统一使用
qName匹配元素:因为你的XML没有使用命名空间,localName是空值,用qName才能正确匹配到标签。 - 在
endElement中处理内容输出:SAX解析到元素结束时,才意味着该元素的文本内容完全接收完毕,这时候输出才是正确的时机。 - 安全的栈操作:弹出元素前先检查栈是否为空,避免空指针异常。
这样修改后,就能精准忽略channel下的内容,只捕获item标签内的title、link和author数据了。
内容的提问来源于stack exchange,提问作者PeakGen
相关产品推荐
相关产品推荐

