使用Java解析未声明命名空间的XML

8

每次我们发布新的Android应用程序,我都需要在我们的网站上更新应用程序信息。因此,我尝试通过在上传到服务器时读取apk中的AndroidManifest.xml来自动更新应用程序信息。

我使用AXMLResourcejdom2来获取AndroidManifest.xml并解析它。

final Namespace NS = Namespace.getNamespace("http://schemas.android.com/apk/res/android");

zipFile = new ZipFile(apkPath);
ZipEntry zipEntry = new ZipEntry("AndroidManifest.xml");
inputStream = zipFile.getInputStream(zipEntry);
AXMLResource axmlResource = new AXMLResource();
axmlResource.read(inputStream);

SAXBuilder saxBuilder = new SAXBuilder();
Document document = saxBuilder.build(new ByteArrayInputStream(axmlResource.toXML().toString().getBytes("UTF-8")));
Element root = document.getRootElement();
System.out.println(root.getAttributeValue("versionCode",NS));
System.out.println(root.getAttributeValue("versionName",NS));

但我总是遇到以下问题:

与“manifest”元素相关联的属性“data:versionCode”的前缀“data”未绑定

我打印了AndroidManifest.xml,发现data命名空间未声明。

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    data:versionCode="344"
    data:versionName="3.2.8"

我查看了Android Studio文档,发现其中使用了已声明的命名空间。

我认为这可能是我们应用程序开发者不规范所导致的。

但是当我进一步思考时,我想知道未声明命名空间的AndroidManifest.xml应用程序为什么能被发布,于是我下载了一些APK文件,如Facebook、YouTube、CentOS、百度云盘和支付宝,发现只有CentOS没有使用未声明命名空间。

对于com.google.android.youtube.apk

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    http:versionCode="1425572340"
    http:versionName="14.25.57"

与“清单”元素相关联的属性“http:versionCode”的前缀“http”未绑定。
对于com.facebook.katana-225.0.0.47.118.apk
<?xml version="1.0" encoding="utf-8"?>
<manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        manifest:versionCode="158425934"
        manifest:versionName="225.0.0.47.118"

与“manifest”元素类型相关联的属性“manifest:versionCode”的前缀未绑定

因此,以下是在 AndroidManifest.xml 中使用未声明命名空间的常见方式,但我该如何解析它?


./aapt d badging release.apk | grep -Po "(?<=\sversion(Code|Name)=')([0-9.]+)" - LF00
aapt将占用约2.6M的磁盘空间,而上述编译代码仅占用52k的空间。 - LF00
2个回答

5

从技术上讲,您的文件是格式良好的XML,但不是命名空间格式良好的XML。绝大多数现代XML工具只能处理(或生成)命名空间格式良好的XML。但是,如果您可以找到仍然处理未命名空间格式良好的XML的XML解析器,则可以使用它以某种方式“修复”您的XML,以满足您的需求(例如,您可以将manifest:versionCode替换为manifest-versionCode)。

然而,与其以这种方式修复XML,还不如一开始就创建命名空间格式良好的XML,这样您就不会受到工具选择的约束。


3

您的问题不在于命名空间,而是在前缀方面。尝试更改:

final Namespace NS = Namespace.getNamespace("http://schemas.android.com/apk/res/android");

转换为:

final Namespace NS = Namespace.getNamespace("data", "http://schemas.android.com/apk/res/android");

没有看到相关的架构,我无法确定有命名空间的架构是否包含 manifest 元素上的匹配属性描述符。我不知道一些类是否进行了透明的模式验证。在您的代码中没有明确地执行这项操作,因此可能是无意义的。

从这些来源接收到的数据中的某个位置,它们应该告诉您使用的前缀是什么(例如“data”,“manifest”,“http”等)。这将使您无需在代码中硬编码“data”前缀。


代码在使用 NS 命名空间之前,在 saxBuilder.build 行抛出错误。 - LF00
抱歉,出现了什么错误?有附加的描述吗? - Stephan Samuel
The prefix “http” for attribute “http:versionCode” associated with an element type “manifest” is not bound - LF00
啊,那就将 getNamespace 调用中的命名空间由 "data" 改为 "http",然后看一下会发生什么。 - Stephan Samuel
代码在到达那一行之前因错误而中断。 - LF00
我们可以在讨论中继续吗? - Stephan Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接