xslt - 合并多个 xml 文件时,如何为子 xml 文件以及父 xml 设置 EntityResolver?
问题描述
我有一个引用其他多个 xml 文件的书 xml 文件。当我尝试在 book.xml 文件上运行 xslt 时,我的代码中的 EntityResolver 解析了 dtd 路径。但是,对于正在合并的子 xml 文件,不会解析 dtd 路径。
示例 sample_book.ditamap
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd">
<bookmap>
<booktitle>
<mainbooktitle>sample book</mainbooktitle>
</booktitle>
<part navtitle="Overview">
<topicref href="../topics/introduction.dita"/>
<topicref href="../topics/install.dita"/>
</part>
</bookmap>
`
Java 代码
public class XMLProcessor {
public void transform(String xmlf, String xslf) throws TransformerConfigurationException, TransformerException, org.xml.sax.SAXException, IOException{
org.xml.sax.XMLReader reader = XMLReaderFactory.createXMLReader();
Transformer transformer;
TransformerFactory factory = TransformerFactory.newInstance();
StreamSource stylesheet = new StreamSource(xslf);
//Source source = StreamSource(xmlf);
//SAXSource source = new SAXSource(new InputSource(xmlf));
// org.xml.sax.XMLReader reader = XMLReaderFactory.createXMLReader();
EntityResolver ent = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
System.out.println(publicId);
System.out.println(systemId);
if(publicId.equals("-//OASIS//DTD DITA BookMap//EN")){
return new InputSource("file:///D:/sample/dtd/bookmap.dtd");
}
return null;
}
};
// sour.setPublicId("file:///D:/sample/dtd/bookmap/dtd/bookmap.dtd");
reader.setEntityResolver(ent);
SAXSource source = new SAXSource(reader, new InputSource(xmlf));
//reader.parse(new InputSource(xmlf));
//StreamSource sourcedoc = new StreamSource(xmlf);
transformer = factory.newTransformer(stylesheet);
try {
transformer.transform(source, new StreamResult(new FileWriter("D:\\sample\\out\\result.xml")));
} catch (IOException ex) {
Logger.getLogger(XMLProcessor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}`
预期结果
`
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns:mf="urn:mf">
<parentpage>
<parentpagename>sample book</parentpagename>
</parentpage>
<part>
<partname>Overview</partname>
<text/>
<level-2>
<concept xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/"
id="introduction" ditaarch:DITAArchVersion="1.3"
domains="(topic concept) (topic abbrev-d) a(props deliveryTarget) (topic equation-d) (topic hazard-d) (topic hi-d) (topic indexing-d) (topic markup-d) (topic mathml-d) (topic pr-d) (topic relmgmt-d) (topic sw-d) (topic svg-d) (topic ui-d) (topic ut-d) (topic markup-d xml-d) "
class="- topic/topic concept/concept ">
<title class="- topic/title ">Introduction</title>
<shortdesc class="- topic/shortdesc "/>
<conbody class="- topic/body concept/conbody ">
<p class="- topic/p ">Sample introduction</p>
</conbody>
</concept>
</level-2>
<text/>
<level-2>
<task xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" id="install"
ditaarch:DITAArchVersion="1.3"
domains="(topic task) (topic abbrev-d) a(props deliveryTarget) (topic equation-d) (topic hazard-d) (topic hi-d) (topic indexing-d) (topic markup-d) (topic mathml-d) (topic pr-d) (topic relmgmt-d) (topic sw-d) (topic svg-d) (topic ui-d) (topic ut-d) (topic markup-d xml-d) (topic task strictTaskbody-c) "
class="- topic/topic task/task ">
<title class="- topic/title ">Install</title>
<shortdesc class="- topic/shortdesc "/>
<taskbody class="- topic/body task/taskbody ">
<context class="- topic/section task/context ">
<p class="- topic/p ">Download xyz installer from here. </p>
</context>
<steps class="- topic/ol task/steps ">
<step class="- topic/li task/step ">
<cmd class="- topic/ph task/cmd ">Double-click the downloader
installer.</cmd>
</step>
<step class="- topic/li task/step ">
<cmd class="- topic/ph task/cmd ">Do this.</cmd>
</step>
<step class="- topic/li task/step ">
<cmd class="- topic/ph task/cmd ">Do that</cmd>
</step>
</steps>
</taskbody>
</task>
</level-2>
</part>
</pages>
`
实际结果
运行 XSLT 时,将显示以下错误消息。当我将 dtd 文件移动到主题文件夹时,错误消失了。
Warning XTDE0540: Ambiguous rule match for /bookmap/booktitle[1] Matches both "element(Q{}booktitle)" on line 54 of >file:///D:/sample/xsl/merge.xsl and "element(Q{}booktitle)" on line 18 of >file:///D:/sample/xsl/merge.xsl Warning at char 11 in
xsl:apply-templates/@select on line 30 column 104 of >merge.xsl: FODC0002: I/O error reporting by XML parser processing file:/D:/sample/sampledoc/topics/introduction.dita: D:\sample \sampledoc\topics\concept.dtd(系统找不到
文件指定)在 xsl:apply-templates/@select 的第 30 行第 104 行的 >merge.xsl: FODC0002: I/O 错误报告的 XML 解析器处理文件中报告的 I/O 错误:/D:/sample/sampledoc/topics/ install.dita: D:\sample\sampledoc\topics\task.dtd (系统找不到指定的>文件)
解决方案
您可以在 Transformer 上设置一个 URIResolver,当您的 XSLT 代码调用 doc() 或 document() 以获取引用的 XML 文件时,将调用该 URIResolver。然后,URIResolver 可以在用于解析这些文件的 XML 解析器上设置一个 EntityResolver。
或者,您可以使用 Apache XMLResolver 来完成所有这些工作,它通过引用 OASIS 定义的格式的目录文件来在 XSLT 和 XML 级别引用 URI。
推荐阅读
- generics - 有没有办法在 Ada(特别是 GNAT)中创建和重用方面集?
- python - 合并/连接包含重复 id 和 TRUE/FALSE 值的行,仅保留 TRUE
- php - 没有登录的 laravel 将我发送到错误的路线
- python - Pandas\Python:作为成对比较的结果创建一个新的数据框
- c# - C# 我正在尝试制作简单的加密器
- mysql - 加入 2 个查询的问题
- c++ - 防止从 bool 到 char 的隐式转换
- node.js - 如何轮换使用 pino-multi-stream 生成的日志文件?
- swiftui - 如何在键盘上方添加工具栏
- asp.net-core - 基于 HTTP 的 ASP.NET Core Blazor 托管身份验证