sax解析中,标签名用localname获取(qname在命名空间下不可靠),属性通过attributes遍历;characters可能分多次调用,需stringbuilder缓存;嵌套结构靠栈维护路径;defaulthandler回调单线程串行,字段无需volatile。

startElement 里怎么拿到标签名和属性
关键就两步:用 localName 或 qName 拿标签名,用 attributes 对象遍历属性。SAX 不建树,所有信息都靠这个回调参数传进来。
常见错误是直接打印 qName 却没处理命名空间——如果 XML 带 xmlns,qName 可能为空或带前缀,此时得优先用 localName;而 attributes.getValue("attr") 在属性不存在时返回 null,不抛异常,但容易漏判空指针。
-
attributes.getLength()返回属性个数,从0开始索引 - 用
attributes.getQName(i)拿属性名,attributes.getValue(i)拿值,比按名字查更安全(避免拼写错) - 如果 XML 有默认命名空间(如
xmlns="http://example.com"),localName有效,qName往往为空字符串
DefaultHandler 的 characters 方法为什么经常读不到完整文本
SAX 不保证一次 characters 调用就把一个文本节点全塞给你——它可能被拆成多次调用,尤其含换行、空格或 CDATA 时。你重写的 startElement 里没法直接拿到文本,得靠 characters + 状态标记配合。
典型翻车场景:在 startElement 里设了个 currentTag = "name",然后指望下一次 characters 就是这个标签的值——结果中间插了注释、换行,或者 JVM 分片推送,characters 被调了三次,第二次还全是空白符。
立即学习“Java免费学习笔记(深入)”;
本文档主要讲述的是Android数据格式解析对象JSON用法;JSON可以将Java对象转成json格式的字符串,可以将json字符串转换成Java。比XML更轻量级,Json使用起来比较轻便和简单。JSON数据格式,在Android中被广泛运用于客户端和服务器通信,在网络数据传输与解析时非常方便。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
- 必须用
StringBuilder缓存每次characters的ch数组片段(注意start和length参数!别直接 new String(ch) - 在
endElement里清空/提交缓存,而不是在characters里立刻处理 - 遇到
ignorableWhitespace回调(如果设置了setFeature("http://xml.org/sax/features/ignore-external-dtd", true)等),空白可能被过滤,但默认不开启,别假设它会帮你 trim
解析嵌套结构时怎么区分同名子标签
没有 DOM 那种父节点引用,只能靠自己维护解析路径栈。比如 <book><author><name>...</name></author></book> 和 <book><title><name>...</name></title></book> 里的两个 name,光看 localName 是一样的,得结合上下文。
最容易被忽略的是:不能只记上一层标签名,得记完整路径或深度状态。有人用布尔变量 inAuthorName,但嵌套三层就崩了;也有人用计数器,但兄弟节点并列时逻辑难维护。
- 推荐在
startElement入栈localName,endElement出栈,用Deque<string></string>存路径 - 判断当前是否为 “author/name” 时,检查栈长度 ≥2 且末尾两个元素是
"author"和"name" - 别在
characters里查栈——万一文本跨多层(比如<a><b>text</b></a>),栈顶已变,得在startElement记下“当前正在进入哪个有意义的叶子节点”
DefaultHandler 子类里字段要不要加 volatile 或同步
不用。SAX 解析器是单线程顺序回调,startElement → 若干 characters → endElement 严格串行,所有回调都在同一个线程里跑。你在 startElement 改的字段,到下一次 characters 一定能读到最新值。
但很多人误以为要线程安全,加了 volatile 或锁,纯属冗余——反而干扰 JIT 优化,还让代码显得可疑。真正该小心的是:别在回调里起新线程去处理数据,那才真需要同步。
- 所有解析状态字段(如
currentText、inTargetTag)声明为普通实例变量即可 - 如果解析完要导出结果,确保在
endDocument之后再访问这些字段,别在回调中途就拿去异步提交 - 多个 SAXParser 实例共用一个
DefaultHandler子类实例?不行——每个解析任务必须用独立 handler 实例,否则状态串了









