合并多个 xml 文件时,除了父 xml 之外,如何为子 xml 文件设置 EntityResolver?

When merging multiple xml files, how can I set EntityResolver for child xml files as well besides the parent xml?

我有一本书 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 reported by XML parser processing file:/D:/sample/sampledoc/topics/introduction.dita: D:\sample\sampledoc\topics\concept.dtd (The system cannot find the

file specified) Warning at char 11 in xsl:apply-templates/@select on line 30 column 104 of >merge.xsl: FODC0002: I/O error reported by XML parser processing file:/D:/sample/sampledoc/topics/install.dita: D:\sample\sampledoc\topics\task.dtd (The system cannot find the >file specified)

您可以在 Transformer 上设置一个 URIResolver,当您的 XSLT 代码调用 doc() 或 document() 以获取引用的 XML 文件时将调用它。然后,URIResolver 可以在用于解析这些文件的 XML 解析器上设置 EntityResolver。

或者,您可以使用 Apache XMLResolver 执行所有这些操作,它通过引用 OASIS 定义的格式的目录文件来在 XSLT 和 XML 级别引用 URI。

感谢迈克尔,我可以解决这个问题。

  1. 在类路径中添加了一个 CatalogManager.properties 文件。

  2. 使用所有 public 个 ID 创建了一个 catalog.xml。

    public class XMLProcessor  {
    
       public void transform(String xmlf, String xslf, String outpath) throws TransformerConfigurationException, TransformerException, org.xml.sax.SAXException, IOException{
    
        org.xml.sax.XMLReader reader = XMLReaderFactory.createXMLReader();
        Transformer transformer = null;
        TransformerFactory factory = TransformerFactory.newInstance();
    
         StreamSource stylesheet = new StreamSource(xslf);
    
            CatalogResolver cr = new CatalogResolver();
            reader.setEntityResolver(cr);
            factory.setURIResolver(cr);
    
            SAXSource source = new SAXSource(reader, new InputSource(xmlf));
    
         transformer = factory.newTransformer(stylesheet);
    
        try {
            transformer.transform(source, new StreamResult(new FileWriter(outpath)));
        } catch (IOException ex) {
            Logger.getLogger(XMLProcessor.class.getName()).log(Level.SEVERE, null, ex);
        }
    
    }
    

    }