我会结合使用JTidy 和JAXB 或XStream。
JTidy 将帮助您清除不需要有效 XHTML 的 HTML 标记。
然后可以使用 JAXB 或 XStream 将 XHTML 解组为 Java 对象并将它们编组回 XML 表单。
可以说,我更熟悉 JAXB,所以我将概述 JAXB 的方式。
使用 JAXB,您可以获取 XHTML 的一些 XML Schema,例如 XHTML 1.0 Strict Schema,然后使用 JAXB 的架构编译器 XJC 对其进行编译。
由于一些命名冲突,编译很可能从一开始就不会成功。例如,xml:lang 和 lang 属性将映射到 Java 类中的相同 lang 属性。此时,您需要使用 binding file 来自定义 XML Schema -> Java 派生。
这是上面提到的架构的样子:
<jaxb:bindings version="1.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc">
<jaxb:bindings schemaLocation="http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd" node="/xs:schema">
<jaxb:schemaBindings>
<jaxb:package name="org.hisrc.w3c.xhtml.v_1_0_strict"/>
</jaxb:schemaBindings>
<jaxb:bindings node="xs:attributeGroup[@name='i18n']/xs:attribute[@ref='xml:lang']">
<jaxb:property name="xmlLang"/>
</jaxb:bindings>
<jaxb:bindings node="xs:element[@name='bdo']/xs:complexType/xs:complexContent/xs:extension/xs:attribute[@ref='xml:lang']">
<jaxb:property name="xmlLang"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
当您(希望)最终成功时,您将获得一个包含大约 90 多个 Java 类的包,这些 Java 类派生自 XHTML 1.0 Strict XML Schema。您将获得像 Map 和 Area 这样的类,其中包含架构中所有元素和属性的属性。
有了这些类,您现在可以解组 XML(最好使用 JTidy 进行预处理)。这看起来像:
JAXBContext context = JAXBContext.newInstance("org.hisrc.w3c.xhtml.v_1_0_strict");
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<Map> mapElement = (JAXBElement<Map>) unmarshaller.unmarshal(source);
Map map = mapElement.getValue();
List<Area> areas = map.getArea();
现在您有了自己的 map 和 areas,可以在 Java 级别上对它们做任何您想做的事情。
最后,您可以将您的 map 编组回某个结果:
Marshaller marshaller = context.createMarshaller();
JAXBElement<Map> mapElement = new JAXBElement<Map>(
new QName("http://www.w3.org/1999/xhtml", "map"),
Map.class, map);
marshaller.marshal(mapElement, result);
所以或多或少是这样的。
(上面的两个代码sn-ps都只是草图,没有经过测试。)
现在是一个小警告。 JAXB 是用于强结构模式的非常好的工具。 XHTML 属于“半结构化”类别,因为它允许大量混合内容、任意顺序的元素等等。这些东西在 JAXB 模式派生类中有时看起来很丑陋。例如,您将获得如下属性:
@XmlElementRefs({
@XmlElementRef(name = "object", namespace = "http://www.w3.org/1999/xhtml", type = org.hisrc.w3c.xhtml.v_1_0_strict.Object.class, required = false),
@XmlElementRef(name = "label", namespace = "http://www.w3.org/1999/xhtml", type = Label.class, required = false),
// 28 lines skipped
@XmlElementRef(name = "strong", namespace = "http://www.w3.org/1999/xhtml", type = Strong.class, required = false),
@XmlElementRef(name = "abbr", namespace = "http://www.w3.org/1999/xhtml", type = Abbr.class, required = false)
})
@XmlMixed
protected List<java.lang.Object> content;
这不是很好。所以 JAXB 可能不太适合该任务
最后,一个小广告块。
免责声明:我领导了一个名为 w3c-schemas 的小型开源项目。该项目使用 JAXB 编译了一些 W3C 模式(例如,XLink 或 XML Schema 本身)。该项目的目标是提供从这些模式编译而来的即用型模式派生类 - 或可用于编译的绑定文件。
所以在回答您的问题时,我刚刚将 XHTML 1.0 Strict 添加到我的项目中。您可以在此处访问相关模块:
以下是您在自己编译 XHTML 1.0 Strict 模式时可以使用的绑定文件:
这与我在上面作为代码 sn-p 发布的绑定文件基本相同。
审稿人注意:在这个答案中,我确实参考了我自己的项目。但是,如果 OP 选择使用 JAXB,我所指的模块和代码与问题非常匹配。