setnamespaceaware(true)必须在newsaxparser()前调用,否则无效;开启后需用startelement的uri和localname参数、atts.getvalue(uri, localname)获取命名空间信息,android旧版本可能抛unsupportedoperationexception。

setNamespaceAware(true) 必须在 newSAXParser() 之前调用
这是最容易出错的地方:一旦 SAXParser 实例已经创建,再调用 setNamespaceAware() 就完全无效。SAX 解析器的命名空间支持是工厂初始化时就决定的,不是运行时可开关的配置。
常见错误现象:startElement() 回调里 getQName() 返回空、getURI() 总是 null、前缀无法解析——十有八九是这一步漏了或顺序错了。
- 正确顺序:先
factory.setNamespaceAware(true),再factory.newSAXParser() - 如果用了
setValidating(true),它和setNamespaceAware(true)不冲突,但两者都得在newSAXParser()前设好 - 默认值是
false,不显式设置就等于关闭命名空间支持,哪怕 XML 文档里写了xmlns
XML 文档必须有 xmlns 声明,且 handler 要用 getURI() + getLocalName()
开启 setNamespaceAware(true) 只是第一步,真正拿到命名空间信息还得靠 DefaultHandler 里正确使用回调参数。很多人还习惯用 getQName(),但在命名空间模式下它不可靠(可能为 null 或不含前缀)。
使用场景:解析像 <envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"></envelope> 这类带前缀的 XML。
立即学习“Java免费学习笔记(深入)”;
-
startElement(String uri, String localName, String qName, Attributes atts)的uri参数才是命名空间 URI,localName是无前缀的本地名 -
qName仅作参考,JDK 实现中可能为 null;不要拿它做逻辑分支 - 如果需要识别特定命名空间下的元素,直接比对
uri字符串(比如"http://www.w3.org/2001/XMLSchema")
setNamespaceAware(true) 会影响 Attribute 解析行为
开启命名空间后,Attributes 对象返回的属性也会按命名空间规则处理,这点常被忽略。原来靠 getValue("xsi:type") 能取到的值,开启后可能失效。
性能影响极小,但兼容性变化明显:属性名也分 uri/localName,不再只认 qName。
- 用
atts.getValue("http://www.w3.org/2001/XMLSchema-instance", "type")替代getValue("xsi:type") - 或者遍历所有属性,用
atts.getURI(i)和atts.getLocalName(i)精确匹配 - 如果 XML 属性没声明命名空间(比如普通
id="123"),它的uri是空字符串"",不是null
Android 上 SAXParserFactory 默认不支持 setNamespaceAware(true)
部分旧版 Android(尤其是 4.x 及更早)的内置 SAX 实现会抛 UnsupportedOperationException,即使代码写对了也会崩。
错误信息:java.lang.UnsupportedOperationException: setNamespaceAware
- 这不是你代码的问题,是系统 XML 库限制;可改用
XmlPullParser(推荐)或引入xerces-for-android - 检测方式:try-catch
setNamespaceAware(true),捕获异常后降级处理(比如放弃前缀解析,只靠qName粗略匹配) - JDK 7+ 和现代 Android(API 28+)基本无此问题,但遗留项目仍需留意
命名空间不是“开了就自动好使”的开关,它是一整套解析契约:工厂要开、文档要有声明、handler 要换参数、属性访问要重写逻辑——漏掉任一环,getURI() 就还是 null。










