代码之家  ›  专栏  ›  技术社区  ›  Tamias

用于多个目录文件(以及目录?XML)和DTDs(以及XSDS)的Java目录解析器,以及指向API以外的更多信息的指针?

  •  0
  • Tamias  · 技术社区  · 6 年前

    我使用的是PTC ARBECTURE编辑器,它最初是在20世纪80年代末的前XML(SGML)日编写的。 组织.custommonkey.xmlunit 以区分XML文件。

    diff工具无法解析文件所需的文件(在Windows上),这些文件使用分号分隔的绝对路径列表指向其查找的各个目录文件位置。 catalog 和/或 catalog.xml 文件夹。这些可以使用 CATALOG 指令。有使用 PUBLIC 映射到相对于特定目录文件的路径的标识符。

    我正在使用这个目录信息分析XML,它可能包含文件实体和XML包含。

    对于某些用例,我可以设置验证 false 这是可行的(假设这两个文件是有效的是合理的),但是对于某些文件,我必须读取目录信息来解析XML中的文件实体。

    我可以要求用户提供到其顶级目录位置的绝对路径列表。但是,我很难选择一个解析器并将其集成到我的代码中。

    我使用Java 1.8,但不介意去10,如果这有助于/简化。看起来9有一些简单的支持 javax.xml.catalog目录 但不是1.8或10。

    如果这很重要,我可以提供我的解析代码,但我不会停留在任何一个解析器上。

    我的代码在下面。我从 LSParser DocumentBuilder 为了 setValidating(false)

    以下是我希望能够使用的其中一个文件的一些摘录:

    <?xml version="1.0" encoding="UTF-8"?>
    <!--Arbortext, Inc., 1988-2016, v.4002-->
    <!DOCTYPE Composer PUBLIC "-//Arbortext//DTD Composer 1.0//EN"
     "../doctypes/composer/composer.dtd" [
    <!ENTITY % stock PUBLIC "-//Arbortext//DTD Fragment - ATI Stock filter list//EN" "../composer/stock.ent">
    %stock;
    ]>
    <?Pub Inc?>
    <Composer>
    <Label>Compose to PDF</Label>
     . . . 
    <Resource>
    <Label></Label>
    <Documentation></Documentation>&epicGenerator;
    &fileSerializer;
    &serverProfiler;
    &clientProfiler;
    &xslTransformer;
    &epicSerializer;
    &switch;
    &errorHandler;
    &namespaceFixer;
    &atiEventConverter;
    &foPropagator;
    &extensionHandler;
    &ditaPostProcessor;
    &ditaStyledElementsTranslator;
    &atictFilter;
    &applicabilityFilter;
    </Resource>
    

    下面是我需要参考的目录文件中的几行:

    PUBLIC "-//Arbortext//ENTITIES SAX Event Upstream Loop//EN" "upstreamLoop.ent"
    PUBLIC "-//Arbortext//ENTITIES keyRef Resolver//EN" "keyRefResolver.ent"
    PUBLIC "-//Arbortext//ENTITIES ATI Change Tracking Filter 1.0//EN" "atictFilter.ent"
    PUBLIC "-//Arbortext//ENTITIES Font Filter 1.0//EN" "fontFilter.ent"
    PUBLIC "-//Arbortext//ENTITIES Simple Attribute Cascader//EN" "simpleAttrCascader.ent"
    

    资源

    叠加溢出

    我也看过 Validate XML using XSD, a Catalog Resolver, and JAXP DOM for XSLT . 我觉得这不太可能解决我的问题,但可能是错误的。

    在线的

    我还查看了以下网站:

    测试用例

    我已经将Java代码、目录结构和XML上传到 http://aapro.net/CatalogTest.zip

    应该可以向我的程序添加一些内容,它接受到test/doctypes文件夹(文件夹,而不是其中的目录文件)的路径,然后用程序提示的“validate”选项成功解析catalogtest.xml文件。其他(昂贵的)sgml/xml感知软件可以做到这一点。一旦给定了test/doctypes文件夹的绝对路径,目录解析器就应该能够按照test/doctypes/catalog文件中的catalog指令执行到test/other/forms/catalog文件,再执行到test/other/forms/forms.dtd。解析器应该能够解析test/other/forms/forms.dtd并使用它来验证test/catalogtest.xml。

    实际上,整个过程应该能够处理这样的目录文件或catalog.xml文件,并且应该能够解析DTD或XSD文件,以及SGML或XML实例。但实际上我并不太关心SGML;在我的工作环境中,仍然只有一些milspec环境使用它。

    多种方法?

    我愿意尝试多个解析器和/或解析器,或者让用户进行选择。

    内联Java代码

    (也在上述zip文件中)

    import java.io.File;
    import javax.swing.JFileChooser;
    import javax.swing.JOptionPane;
    import javax.swing.filechooser.FileNameExtensionFilter;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import org.w3c.dom.Document;
    
    public class ParseXmlWithCatalog {
    
            public static void main(String[] args) {
                    int validating = JOptionPane.showOptionDialog(null, "Do you want validation?", "Please choose \"Yes\" for validation",
                                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, JOptionPane.YES_OPTION);
                    parseDoc(getFile(args), validating == JOptionPane.YES_OPTION);
            }
    
            private static boolean parseDoc(File inFile, boolean validate) {
                    if (inFile == null) {
                            JOptionPane.showMessageDialog(null, "Failure opening input XML.");
                    }
                    try {
                            /*
                            System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMImplementationSourceImpl");
                            DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
                            DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
                            LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
                            LSParserFilter filter = new InputFilter();
                            builder.setFilter(filter);
                    */
                            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
                            if (!validate) {
                                    builderFactory.setValidating(false);
                                    builderFactory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
                            }
                            DocumentBuilder builder = builderFactory.newDocumentBuilder();
    
                            Document testDoc = builder.parse(inFile.getPath());
                            System.out.println(testDoc.getFirstChild().getNodeName());
                    } catch (Exception exc) {
                            JOptionPane.showMessageDialog(null, "Failure parsing input XML: " + exc.getMessage());
                            return false;
                    }
                    return true;
            }
    
            public static File getFile(String[] args) {
                    if (args.length > 1) {
                            JOptionPane.showMessageDialog(null, "Too many arguments.");
                            return null;
                    }
                    if (args.length == 1) {
                            return new File(args[0]);
                    }
                    JFileChooser fileChooser = new JFileChooser();
                    fileChooser.setMultiSelectionEnabled(false);
                    fileChooser.setDialogTitle("Select 1 XML file");
                    FileNameExtensionFilter filter = new FileNameExtensionFilter("XML Files", "xml", "ditamap", "dita", "style");
                    fileChooser.setFileFilter(filter);
                    int response = fileChooser.showOpenDialog(null);
                    if (response != JFileChooser.APPROVE_OPTION) {
                            // aborted
                            return null;
                    }
                    return fileChooser.getSelectedFile();
    
            }
    
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   mzjn    6 年前

    ApacheXML公共资源解析器同时支持OASISXML目录和旧的OASISTR9401目录格式。见 https://xerces.apache.org/xml-commons/components/resolver/

    要在测试项目中启用目录查找,请执行以下操作:

    1. 从下载XML通用解析程序 http://xerces.apache.org/mirrors.cgi#binary .

    2. 提取resolver.jar并将其添加到类路径中。

    3. 创建一个名为catalogManager.properties的文本文件,并将其放在类路径上。在此文件中,添加目录路径:

      catalogs=./doctypes/catalog
      

      目录文件的位置也可以通过 xml.catalog.files Java系统属性。

    4. 在parsexmlwithcatalog.java中,添加 import 语句并创建 CatalogResolver . 将该实例设置为分析器的 EntityResolver :

      import org.apache.xml.resolver.tools.CatalogResolver;
      ...
      
      CatalogResolver cr = new CatalogResolver();
      builder.setEntityResolver(cr);
      
        2
  •  0
  •   Tamias    6 年前

    我之所以发布这个示例代码,是因为它结合了mzjn建议的org.apache.xml.resolver.tools.catalogsolver的使用,并成功地使用了我的示例 http://aapro.net/CatalogTest.zip . 也就是说,如果我运行它,并用yes(我想要验证)回答第一个提示,用test\doctypes文件夹的绝对路径回答第二个提示,然后浏览到catalogtest.xml,它成功地遵循test\doctypes中的catalog指令到“..other/forms/catalog”,后者依次指定tDTD的位置为:“public”-//test//forms document type//en“”forms.dtd”,并告诉我我的顶级节点称为“form”。

    现在,我将把这个解决方案合并到我的XML diff程序中。如果我发现需要调整来处理多条目目录路径和/或处理目录和catalog.xml文件的混合,我将发布一个更新。但那可能需要几个星期(或更长时间),我认为这段代码到了有人会发现它有用的程度。

    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Map.Entry;
    import java.util.Properties;
    
    import javax.swing.JFileChooser;
    import javax.swing.JOptionPane;
    import javax.swing.filechooser.FileNameExtensionFilter;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    import org.apache.xml.resolver.tools.CatalogResolver;
    import org.w3c.dom.Document;
    
    public class ParseXmlWithCatalog {
    
            // Offer end-user the convenience of not having to specify which will be used,
            // catalog and/or catalog.xml.
            private static FilenameFilter catalogFileFilter = new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                            if (name.equals("catalog") || name.equals("catalog.xml")) {
                                    return true;
                            } else {
                                    return false;
                            }
                    }
            };
    
            public static void main(String[] args) {
                    int validating = JOptionPane.showOptionDialog(null, "Do you want validation?",
                                    "Please choose \"Yes\" for validation", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
                                    null, JOptionPane.YES_OPTION);
                    if (validating == JOptionPane.YES_OPTION) {
                            String catPath = JOptionPane.showInputDialog(null,
                                            "Please enter semi-colon-separated list of absolute paths to catalog folders, in desired search order; these are the locations of catalog or catalog.xml files, not the filenames.",
                                            "Enter catalog path", JOptionPane.QUESTION_MESSAGE);
                            String[] catLocs = catPath.split(";");
                            StringBuilder sb = new StringBuilder();
                            for (String catLoc : catLocs) {
                                    File[] catFiles = new File(catLoc).listFiles(catalogFileFilter);
                                    for (File catFile : catFiles) {
                                            if (sb.length() > 0) {
                                                    sb.append(";");
                                            }
                                            sb.append(catFile.toURI());
                                    }
                            }
                            System.setProperty("xml.catalog.files", sb.toString());
                            System.out.println(
                                            "Using the following top-level catalog files:\n" + System.getProperty("xml.catalog.files"));
                            System.setProperty("relative-catalogs", "yes");
                    }
                    parseDoc(getFile(args), validating == JOptionPane.YES_OPTION);
            }
    
            private static boolean parseDoc(File inFile, boolean validate) {
                    if (inFile == null) {
                            JOptionPane.showMessageDialog(null, "Failure opening input XML.");
                    }
                    try {
                            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
                            if (!validate) {
                                    builderFactory.setValidating(false);
                                    builderFactory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
                            }
                            DocumentBuilder builder = builderFactory.newDocumentBuilder();
                            CatalogResolver resolver = new CatalogResolver();
                            builder.setEntityResolver(resolver);
                            Document testDoc = builder.parse(inFile.getPath());
                            JOptionPane.showMessageDialog(null,
                                            "The top level node is \"" + testDoc.getFirstChild().getNodeName() + "\"");
                    } catch (Exception exc) {
                            JOptionPane.showMessageDialog(null, "Failure parsing input XML: " + exc.getMessage());
                            return false;
                    }
                    return true;
            }
    
            public static File getFile(String[] args) {
                    if (args.length > 1) {
                            JOptionPane.showMessageDialog(null, "Too many arguments.");
                            return null;
                    }
                    if (args.length == 1) {
                            return new File(args[0]);
                    }
                    JFileChooser fileChooser = new JFileChooser();
                    fileChooser.setMultiSelectionEnabled(false);
                    fileChooser.setDialogTitle("Select 1 XML file");
                    FileNameExtensionFilter filter = new FileNameExtensionFilter("XML Files", "xml", "ditamap", "dita", "style");
                    fileChooser.setFileFilter(filter);
                    int response = fileChooser.showOpenDialog(null);
                    if (response != JFileChooser.APPROVE_OPTION) {
                            // aborted
                            return null;
                    }
                    return fileChooser.getSelectedFile();
            }
    }
    
    推荐文章