Ubuntu 22.04 安装 Apache XML Commons Resolver 指南

在 Ubuntu 22.04 上从零安装 Apache XML Commons Resolver 1.2(坐标 xml-resolver:xml-resolver:1.2),覆盖 JDK 17 与 Maven 环境、Maven 依赖与 jar 直用两种方案、手写 OASIS catalog 离线解析 DTD 的最小验证与内置命令行工具,命令回显均实测通过。

Apache XML Commons ResolverApache XML Commons Resolver2026/10/15

Ubuntu 22.04 安装 Apache XML Commons Resolver 指南

目标:在 Ubuntu 22.04 上从零搭建 Apache XML Commons Resolver 1.2 的开发与运行环境(JDK 17 + Maven 3.6.3 + 中央仓库依赖),手写一份 OASIS XML Catalog 并跑通「不带 catalog 解析失败 → 带 catalog 离线解析成功」的最小验证,同时覆盖 jar 直用与内置命令行工具;本文全部命令与回显均已在 Ubuntu 22.04 实测通过。

Apache XML Commons Resolver(xml-commons 子项目的 Resolver 组件)是 OASIS XML Catalog 标准的 Java 实现:它把 XML 文档里的 DTD/XSD 外部引用(PUBLIC 标识符、SYSTEM 系统标识符、URI)映射到本地 catalog 文件登记的本地资源,让解析器不再联网拉取外部实体。它是一个纯 Java 微型库(jar 仅 84091 字节),没有独立进程与常驻服务,安装的本质就是「装好 JDK/构建工具 → 引入依赖 → 手写 catalog → 跑最小验证程序」。本文给出两种落地方式:面向开发的 Maven 依赖方案,以及面向无构建体系场景的 jar 直用方案。

一、环境信息

本节先固定可复现的基线环境,后续所有命令均在此环境执行。列出操作系统、架构、JDK、构建工具与组件版本,便于读者对照复现。

  • 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
  • 架构:x86_64
  • JDK:OpenJDK 17.0.20.1(apt 包 openjdk-17-jdk)
  • 构建工具:Apache Maven 3.6.3
  • 组件版本:xml-resolver 1.2(Maven 坐标 xml-resolver:xml-resolver:1.2)
  • jar 事实:84091 字节,字节码 major version 45(Java 1.1 基线),零传递依赖
  • 验证用工作目录:/root/xresolver-demo(工程)、/root/xresolver-work(DTD/XSD/catalog 素材)

系统与架构确认(实时回显):

cat /etc/os-release | head -2
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
uname -m
x86_64

💡 说明:XML Commons Resolver 是库而非服务,环境中不存在需要常驻的守护进程;「安装完成」的判定标准是能用一份 catalog 离线解析一个引用外部 DTD 的 XML,而不是某个端口处于监听状态。

二、前置条件

本节说明安装前必须满足的条件。Ubuntu 22.04 自带可用的软件源,联网即可通过 apt 获取 JDK 与 Maven;组件本身从 Maven 中央仓库获取。

  1. 具有 root 或 sudo 权限的 Ubuntu 22.04 系统。
  2. 可访问 Ubuntu 官方软件源(apt update 能正常拉取索引)。
  3. 可访问 Maven 中央仓库 repo1.maven.org(xml-resolver 无官方独立下载站发布 jar,中央仓库是唯一权威来源,本文实测网络直连可达)。
  4. 至少 2 GB 可用磁盘空间(JDK + Maven + 依赖合计约 500 MB)。
  5. 已安装 curl(用于连通性与版本元数据检查):apt-get install -y curl。

中央仓库连通性确认(实时回显):

curl -sI --max-time 20 https://repo1.maven.org/maven2/xml-resolver/xml-resolver/ | head -1
HTTP/2 200

三、版本选型说明

本节给出 XML Commons Resolver 的版本谱系。它没有传统的官方下载目录,版本事实以 Maven 中央仓库的 maven-metadata.xml 为准(实时回显):

curl -s --max-time 30 https://repo1.maven.org/maven2/xml-resolver/xml-resolver/maven-metadata.xml | grep -E "<latest>|<release>|<version>|<lastUpdated>"
    <latest>1.2</latest>
    <release>1.2</release>
      <version>1.1</version>
      <version>1.2</version>
    <lastUpdated>20170926150429</lastUpdated>
版本状态说明
1.1已被取代早期发布,仅存档
1.2(当前 latest/release)最终版本2006-12-22 构建(jar 内文件日期),中央仓库索引最后更新 2017-09-26

两个必须知道的实测事实:

  • 坐标只有一套:Maven Central 上该组件只有 xml-resolver:xml-resolver 这一个坐标。部分资料提到的新坐标 org.apache.xmlresolver:xmlresolver 在中央仓库实测不存在(实时回显):
curl -sI --max-time 20 https://repo1.maven.org/maven2/org/apache/xmlresolver/xmlresolver/maven-metadata.xml | head -1
HTTP/2 404
  • 微型库如实披露:1.2 是一个停止维护十余年的最终版。jar 仅 84091 字节、字节码 major version 45(Java 1.1 基线,JDK 8/11/17 均可运行,本文实测 17)、pom 无 <dependencies> 节(零传递依赖,第四章依赖树实测验证)。它解决的是「外部实体离线解析」这一稳定问题,API 自 2006 年起未变,因此生产可用;但这意味着它不会跟进新特性,新代码可同步评估 JDK 9+ 内置的 javax.xml.catalog(对比见第 3 篇《Apache XML Commons Resolver 1.2 Catalog 解析实战详解》第八章)。

本文实际采用 1.2,理由是它是中央仓库 latest/release 的最终版本,且对 JDK 17 完全兼容。

四、方案 A:Maven 依赖安装(在线,推荐)

本节面向常规 Java 项目开发,通过 apt 安装 JDK 与 Maven,再用 Maven 坐标引入 xml-resolver 依赖并跑通最小验证程序。这是最贴合工程实践的方式。

4.1 方案说明

方案 A 的链路是:apt 安装 openjdk-17-jdk 与 maven → 在 pom.xml 中声明 xml-resolver:xml-resolver:1.2 → Maven 自动从中央仓库下载 jar 到本地仓库 → 准备 DTD 与 catalog 素材 → 编译并运行「无 catalog 失败 / 有 catalog 成功」的对照验证程序。优点是版本由 pom 统一管控、依赖自动解析;缺点是首次构建需要联网。

4.2 安装 JDK 17

Ubuntu 22.04 官方源内置 openjdk-17-jdk,直接安装即可:

apt-get update -qq && apt-get install -y openjdk-17-jdk

安装后确认版本:

java -version
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)

验证点:java -version 能输出 17.0.x 即表示 JDK 就绪;若仍指向旧版本,用 update-alternatives --config java 选择 17。

4.3 安装 Maven

apt-get install -y maven

确认版本与 Maven 实际使用的 JDK:

mvn -version | head -3
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64

验证点:Java version 一行显示 17.0.20.1,说明 Maven 已绑定到 JDK 17;Ubuntu 版 Maven 通过 PATH 中的 java 定位 JDK,JAVA_HOME 为空也能正常构建(见第七章),无需额外设置。

4.4 创建工程并引入依赖

建立一个标准 Maven 工程并在 pom.xml 中声明依赖:

mkdir -p /root/xresolver-demo/src/main/java /root/xresolver-work/dtd /root/xresolver-work/xml /root/xresolver-work/xsd

pom.xml(完整内容,文件路径 /root/xresolver-demo/pom.xml):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>demo</groupId>
  <artifactId>xresolver-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>xml-resolver</groupId>
      <artifactId>xml-resolver</artifactId>
      <version>1.2</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明关键配置:

  • xml-resolver:xml-resolver:1.2:唯一运行期依赖,Maven 会自动下载并缓存到 ~/.m2/repository/xml-resolver/xml-resolver/1.2/。该库零传递依赖,声明这一项即引入全部能力。
  • maven.compiler.release=17:按 JDK 17 语义编译;xml-resolver 1.2 自身是 major 45 的远古字节码,与编译目标互不影响。
  • maven-compiler-plugin 显式固定 3.11.0:Maven 3.6.3 默认绑定的 compiler 插件是 3.1,不认识 maven.compiler.release 属性,会按 source/target=1.5 编译并被 JDK 17 拒绝(报 Source option 5 is no longer supported)。
  • project.build.sourceEncoding=UTF-8:源码含中文注释时防止按平台默认编码编译报 unmappable character。

4.5 最小验证素材与代码

验证目标是同一份 XML「不带 catalog 解析失败、带 catalog 离线解析成功」。先准备三个素材文件。

本地 DTD(文件路径 /root/xresolver-work/dtd/config.dtd):

<!-- 最小化配置 DTD:作为被 catalog 映射的本地实体 -->
<!ELEMENT config (property+)>
<!ATTLIST config version CDATA "1.0">
<!ELEMENT property EMPTY>
<!ATTLIST property name  CDATA #REQUIRED
                   value CDATA #REQUIRED>

XML 实例(文件路径 /root/xresolver-work/xml/config-public.xml),DOCTYPE 声明的系统标识符指向一个不可达的域名 dtd.example.invalid:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config PUBLIC "-//Example//DTD Config 1.0//EN" "http://dtd.example.invalid/config.dtd">
<config version="1.0">
  <property name="host" value="db1.example.internal"/>
  <property name="port" value="5432"/>
</config>

OASIS XML Catalog(文件路径 /root/xresolver-work/catalog.xml),把上面的公开标识符与系统标识符映射到本地 DTD:

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="public">
  <!-- PUBLIC 映射:公开标识符 → 本地 DTD -->
  <public publicId="-//Example//DTD Config 1.0//EN" uri="dtd/config.dtd"/>
  <!-- SYSTEM 映射:系统标识符(URL)→ 本地 DTD -->
  <system systemId="http://dtd.example.invalid/config-sys.dtd" uri="dtd/config.dtd"/>
  <system systemId="http://dtd.example.invalid/config.dtd" uri="dtd/config.dtd"/>
  <!-- URI 映射:XSD 等 namespace/schemaLocation 资源 → 本地 XSD -->
  <uri name="http://schemas.example.invalid/config.xsd" uri="xsd/config.xsd"/>
</catalog>

验证程序 ResolveDemo.java(文件路径 /root/xresolver-demo/src/main/java/ResolveDemo.java,默认包直接放约定目录):

import org.apache.xml.resolver.CatalogManager;
import org.apache.xml.resolver.tools.CatalogResolver;

import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 * 最小验证程序:对比「不带 catalog」与「带 catalog」解析同一份引用外部 DTD 的 XML。
 * 用法:java ResolveDemo nocatalog   /   java ResolveDemo catalog
 */
public class ResolveDemo {

    static final String CATALOG = "/root/xresolver-work/catalog.xml";
    static final String PUBLIC_ID = "-//Example//DTD Config 1.0//EN";
    static final String BAD_SYSID = "http://dtd.example.invalid/config.dtd";
    static final String XML_FILE = "/root/xresolver-work/xml/config-public.xml";

    public static void main(String[] args) throws Exception {
        boolean withCatalog = args.length > 0 && args[0].equals("catalog");
        SAXParserFactory factory = SAXParserFactory.newInstance();
        XMLReader reader = factory.newSAXParser().getXMLReader();

        if (withCatalog) {
            CatalogManager manager = new CatalogManager();
            manager.setIgnoreMissingProperties(true);
            manager.setUseStaticCatalog(false);
            manager.setCatalogFiles(CATALOG);
            CatalogResolver resolver = new CatalogResolver(manager);
            InputSource resolved = resolver.resolveEntity(PUBLIC_ID, BAD_SYSID);
            System.out.println("resolveEntity -> " + (resolved == null ? "null" : resolved.getSystemId()));
            reader.setEntityResolver(resolver);
            System.out.println("== with catalog: " + CATALOG + " ==");
        } else {
            System.out.println("== without catalog ==");
        }

        final String[] root = {"(none)"};
        reader.setContentHandler(new DefaultHandler() {
            public void startElement(String uri, String localName, String qName, Attributes atts) {
                if (root[0].equals("(none)")) {
                    root[0] = qName.isEmpty() ? localName : qName;
                }
            }
        });

        long t0 = System.currentTimeMillis();
        try {
            reader.parse(XML_FILE);
            System.out.println("parse OK, root=" + root[0] + ", cost=" + (System.currentTimeMillis() - t0) + " ms");
        } catch (Exception e) {
            System.out.println("parse FAILED after " + (System.currentTimeMillis() - t0) + " ms");
            throw e;
        }
    }
}

逐项说明核心逻辑:

  • CatalogManager manager = new CatalogManager() + setIgnoreMissingProperties(true):新建独立的管理器实例,classpath 中没有 CatalogManager.properties 时也不告警(properties 文件配置路线见第七章)。
  • manager.setCatalogFiles(CATALOG):程序化指定 catalog 文件,等价于 properties 文件里的 catalogs 键。
  • new CatalogResolver(manager):Apache Resolver 的 JAXP 适配器,实现 org.xml.sax.EntityResolver,挂到 XMLReader 后解析器遇到外部实体就先问 catalog。
  • resolveEntity(PUBLIC_ID, BAD_SYSID):直接验证映射结果,命中时返回的 InputSource 的 systemId 是 file: 本地路径。
  • 不带 catalog 分支:解析器保持默认行为,遇到外部 DTD 会按系统标识符发起真实网络请求。

4.6 编译与运行验证

编译并确认依赖落库:

cd /root/xresolver-demo && mvn -q compile; echo "EXIT=$?"
EXIT=0
ls -l /root/.m2/repository/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar
-rw-r--r-- 1 root root 84091 Oct 15 13:38 /root/.m2/repository/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar

依赖树确认零传递依赖:

mvn -B dependency:tree 2>/dev/null | grep xml-resolver
[INFO] \- xml-resolver:xml-resolver:jar:1.2:compile

解读:依赖树中除工程自身外只有 xml-resolver:xml-resolver:1.2 一个节点,与 pom 无 <dependencies> 节的事实一致,不会拖入任何其他 jar。

先跑「不带 catalog」的对照(预期失败):

java -Dfile.encoding=UTF-8 -cp target/classes:/root/.m2/repository/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar ResolveDemo nocatalog 2>&1 | head -4
== without catalog ==
parse FAILED after 158 ms
Exception in thread "main" java.net.UnknownHostException: dtd.example.invalid
        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:572)

再跑「带 catalog」(预期离线成功):

java -Dfile.encoding=UTF-8 -cp target/classes:/root/.m2/repository/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar ResolveDemo catalog
resolveEntity -> file:/root/xresolver-work/dtd/config.dtd
== with catalog: /root/xresolver-work/catalog.xml ==
parse OK, root=config, cost=3 ms

结果解读:不带 catalog 时解析器对 http://dtd.example.invalid/config.dtd 发起真实 DNS 解析并抛出 UnknownHostException(158 ms 后失败);带 catalog 后同一个外部引用被映射为 file:/root/xresolver-work/dtd/config.dtd,3 ms 内离线解析成功。这表示 xml-resolver 1.2 已在 JDK 17 上完整可用。

五、方案 B:jar 直用(离线友好)

本节面向没有 Maven/构建体系的场景,直接从 Maven 中央仓库获取单个 jar,用 javac + java 完成编译运行,不依赖任何构建工具。

5.1 方案说明

链路是:从 repo1.maven.org 下载 xml-resolver-1.2.jar → 校验 sha1 → 用 javac -cp 编译源码 → 用 java -cp 运行;jar 自带 Main-Class,还能直接当命令行工具用。适用于离线环境、脚本化部署或纯粹想「拿到 jar 就能用」的读者。

5.2 下载与完整性校验

mkdir -p /root/jar-run && cd /root/jar-run
curl -sO --max-time 60 https://repo1.maven.org/maven2/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar
curl -sO --max-time 30 https://repo1.maven.org/maven2/xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar.sha1
ls -l xml-resolver-1.2.jar
-rw-r--r-- 1 root root 84091 Oct 15 13:45 xml-resolver-1.2.jar

校验 sha1(期望值取自 .sha1 文件第一列,实测值必须逐字一致):

echo "期望: $(cut -d' ' -f1 xml-resolver-1.2.jar.sha1)"
echo "实测: $(sha1sum xml-resolver-1.2.jar | awk '{print $1}')"
期望: 3d0f97750b3a03e0971831566067754ba4bfd68c
实测: 3d0f97750b3a03e0971831566067754ba4bfd68c

⚠️ 注意:.sha1 文件内容是「摘要 + 构建路径」(如 3d0f...d68c ./xml-resolver/xml-resolver/1.2/xml-resolver-1.2.jar),比对时取第一列摘要即可;若不一致说明下载包损坏或被篡改,须删除后重新下载,切勿跳过校验直接使用。

5.3 javac 编译与 java 运行

复用 4.5 节的 ResolveDemo.java 与素材文件,用官方 jar 作为编译与运行期 classpath:

cd /root/jar-run
cp /root/xresolver-demo/src/main/java/ResolveDemo.java .
javac -encoding UTF-8 -cp xml-resolver-1.2.jar -d out ResolveDemo.java
java -Dfile.encoding=UTF-8 -cp out:xml-resolver-1.2.jar ResolveDemo catalog
resolveEntity -> file:/root/xresolver-work/dtd/config.dtd
== with catalog: /root/xresolver-work/catalog.xml ==
parse OK, root=config, cost=3 ms
java -Dfile.encoding=UTF-8 -cp out:xml-resolver-1.2.jar ResolveDemo nocatalog 2>&1 | head -3
== without catalog ==
parse FAILED after 139 ms
Exception in thread "main" java.net.UnknownHostException: dtd.example.invalid

验证点:java -cp 方式成功完成映射与离线解析,且无 NoClassDefFoundError,说明 jar 直跑可用;无 catalog 的失败对照与 4.6 节一致。

5.4 jar 自带的命令行工具(可选)

该 jar 的 META-INF/MANIFEST.MF 中 Main-Class: org.apache.xml.resolver.apps.resolver,可直接 java -jar 调用。查看用法:

cd /root/jar-run && java -jar xml-resolver-1.2.jar 2>&1 | head -6
Usage: resolver [options] keyword

Where:

-c catalogfile  Loads a particular catalog file.
-n name         Sets the name.
-p publicId     Sets the public identifier.
-s systemId     Sets the system identifier.

用 -c 指定 catalog、-p 指定公开标识符、末尾关键字 public 表示查询类型:

java -jar xml-resolver-1.2.jar -c /root/xresolver-work/catalog.xml -p '-//Example//DTD Config 1.0//EN' public
Resolve PUBLIC (publicid, systemid):
  public id: -//Example//DTD Config 1.0//EN
Result: file:/root/xresolver-work/dtd/config.dtd

⚠️ 注意:命令行工具启动时若 classpath 中没有 CatalogManager.properties 会先打印一行 Cannot find CatalogManager.properties——这是无害告警,-c 显式传入的 catalog 正常生效,Result: 行给出映射结果即为成功。

六、方案对比与选择建议

本节汇总两种方案的差异,给出选型建议。两种方案产出的是同一份 xml-resolver 1.2 代码,差别仅在获取与装配方式。

维度方案 A:Maven 依赖方案 B:jar 直用
获取方式Maven 自动从中央仓库解析下载手工下载单个 jar 并校验 sha1
是否联网首次构建需联网仅下载时需要联网
依赖版本管控pom 统一声明,可锁版本无,靠文件命名区分
多依赖协同自动处理(本库零传递依赖,无额外收益)手工拼 classpath
命令行工具需从本地仓库找 jar 再 java -jarjar 就在手边,直接可用
适用场景常规工程开发离线服务器、临时验证、无构建体系

选型建议:项目有构建体系一律选方案 A,版本管控与后续升级全自动化;老服务器临时验证、或要把 catalog 能力嵌进既有脚本(配合 5.4 节命令行工具)选方案 B。两者也可共存——工程内用方案 A 开发,分发侧用方案 B。

七、基础配置说明

XML Commons Resolver 的「配置」就是一份 catalog 文件加上一个可选的 CatalogManager.properties。catalog 文件是核心(第五章素材已给出完整样例),这里逐项说明其条目语义:

  • <public publicId="…" uri="…"/>:按公开标识符映射。DOCTYPE 同时带 PUBLIC 与 SYSTEM 标识符时,受 <catalog prefer="public"> 控制优先查 public 条目,命中即不再联网。
  • <system systemId="…" uri="…"/>:按系统标识符(通常是 URL)映射,用于没有公开标识符的 DOCTYPE、外部实体引用等。
  • <uri name="…" uri="…"/>:按 URI 原样映射,用于 XSD 的 schemaLocation、命名空间文档等非实体资源(XSD 完整实战见第 3 篇)。
  • uri 属性值是相对路径时,相对 catalog 文件所在目录解释(如 dtd/config.dtd 相对于 /root/xresolver-work/)。
  • catalog 文件可以链式引用:<nextCatalog catalog="…"/> 把多份 catalog 串起来;本文样例未用到。

CatalogManager.properties(classpath 根目录)是程序化配置之外的另一条配置路线,供 CatalogManager.getStaticManager() 静态单例读取。文件路径 /root/xresolver-demo/src/main/resources/CatalogManager.properties:

catalogs=/root/xresolver-work/catalog.xml
verbosity=1
relative-catalogs=yes
ignore-missing-properties=yes

⚠️ 注意:xml-resolver 1.2 的属性键名不带 xml.catalog. 前缀——catalog 文件列表的键是 catalogs(多文件用 ; 分隔),其余常用键为 verbosity、relative-catalogs、ignore-missing-properties。写成 xml.catalog.files=… 会被静默忽略并回落默认值 ./xcatalog(实测复现过:文件被找到但键名不匹配,打印 CatalogManager.properties: catalogs not found.)。

环境变量 JAVA_HOME:Ubuntu 版 Maven 在 JAVA_HOME 为空时按 PATH 中的 java(由 update-alternatives 指向 JDK 17,见 4.3 节 mvn -version 回显的 runtime 一行)定位 JDK,实测无需设置即可构建;仅当手工安装 JDK 或需要固化绑定时再显式导出:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

八、验证清单

安装是否成功,用下面五项逐条核对(全部为本文实测值):

检查项预期(实测值)不符时排查
java -versionopenjdk version "17.0.20.1"update-alternatives --config java 选 17
mvn -version 的 Java version 行17.0.20.1见第七章 JAVA_HOME 说明
mvn -q compile 退出码EXIT=0编译器插件未固定 3.11.0 → 4.4 节
ResolveDemo nocatalogUnknownHostException: dtd.example.invalid素材文件路径不对(/root/xresolver-work/…)
ResolveDemo catalogresolveEntity -> file:/root/xresolver-work/dtd/config.dtd 与 parse OK, root=configcatalog 未生效 → 第九章 Q3

九、常见问题(FAQ)

Q1:mvn compile 报 Source option 5 is no longer supported 或 invalid flag: --release 怎么办? 前者是 Maven 3.6.3 默认 compiler 插件 3.1 不认识 maven.compiler.release,退回 source/target=1.5 被 JDK 17 拒绝;后者是 JAVA_HOME/PATH 指向了 JDK 8(JDK 8 的 javac 不认识 --release 参数)。修复:按 4.4 节把 maven-compiler-plugin 固定为 3.11.0,并确认 4.3 节 mvn -version 的 Java version 行是 17。(CentOS 8 上第二个坑更常见,见第 2 篇《CentOS 8 安装 Apache XML Commons Resolver 指南》。)

Q2:运行报 Could not find or load main class ResolveDemo? classpath 未包含编译产物或 jar。确认命令为 java -cp target/classes:xml-resolver-1.2.jar ResolveDemo(-cp 两段都要有);且源码文件在 src/main/java/ 约定目录下编译过(target/classes 里存在 ResolveDemo.class)。

Q3:带 catalog 运行仍报 UnknownHostException,catalog 没生效? 三个高频原因:一是 setCatalogFiles()/catalogs 指向的路径不存在(catalog 装载失败是静默的,先把 verbosity 调到 2 看装载日志);二是 properties 键名写成了 xml.catalog.files(1.2 的键是 catalogs,见第七章);三是 catalog 里的 <system systemId> 与 XML 里的系统标识符字符串不一致(映射是精确字符串匹配,不是前缀匹配)。本文 4.5 节 catalog 同时登记了 config.dtd 与 config-sys.dtd 两个 systemId,就是为了让两种写法都命中。

Q4:中文输出变问号? 默认 POSIX locale 下 JVM 按 ASCII 输出中文。运行时加 -Dfile.encoding=UTF-8(本文所有运行命令已带),或 export LANG=C.UTF-8。

Q5:xml-resolver 1.2 能跑在 JDK 8/11/17 上吗? 能。实测其字节码 major version 为 45(Java 1.1 基线),本文在 JDK 17 上完整跑通全部验证;JDK 8/11 仅是更低基线,不受影响。

Q6:java -jar xml-resolver-1.2.jar 报 Cannot find CatalogManager.properties? 无害告警(见 5.4 节)。要消除它,把第七章的 CatalogManager.properties 放进 classpath(如 java -cp /root/xresolver-work:xml-resolver-1.2.jar org.apache.xml.resolver.apps.resolver …)。

十、卸载与清理

XML Commons Resolver 本身不产生系统级安装,卸载即移除依赖与本地文件。

移除工程、素材与 jar 直用目录:

rm -rf /root/xresolver-demo /root/xresolver-work /root/jar-run

移除 Maven 本地仓库中的 xml-resolver(影响所有工程,慎用):

rm -rf $HOME/.m2/repository/xml-resolver

卸载 JDK 与 Maven(仅当不再需要)。先以 -s 预演确认将删除的包,无误后去掉 -s 真正执行:

apt-get -s purge -y openjdk-17-jdk maven
The following packages will be REMOVED:
Purg maven [3.6.3-5]
Purg openjdk-17-jdk [17.0.20.1+1-1~22.04]

确认无误后真正卸载:

apt-get purge -y openjdk-17-jdk maven && apt-get autoremove -y

十一、参考链接

  1. Apache XML Commons Resolver 组件主页(pom 内官方 URL):http://xml.apache.org/commons/components/resolver/
  2. Xerces 站点上的 XML Commons 文档:https://xerces.apache.org/xml-commons/components/resolver/
  3. OASIS XML Catalogs 1.0 规范(catalog.xml 条目语义):https://www.oasis-open.org/committees/entity/spec.html
  4. Maven 中央仓库 xml-resolver 坐标页:https://repo1.maven.org/maven2/xml-resolver/xml-resolver/
  5. 版本元数据(maven-metadata.xml):https://repo1.maven.org/maven2/xml-resolver/xml-resolver/maven-metadata.xml
  6. JDK 17 内置 javax.xml.catalog 包文档(对比路线):https://docs.oracle.com/en/java/javase/17/docs/api/java.xml/javax/xml/catalog/package-summary.html