Средство распознавания каталога Java для нескольких файлов каталога (а также catalog.xml) и DTD (а также XSD) и указатель на дополнительную информацию, а не только на API?

Я работаю с PTC Arbortext Editor, который был изначально написан в дни до XML (SGML) в конце 1980-х годов. Приложение Java использует org.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"

Ресурсы

Переполнение стека

Я также рассмотрел валидацию XML с использованием XSD, резолвера каталогов и JAXP DOM для XSLT. Я чувствую, что это вряд ли решит мою проблему, но может ошибаться.

онлайн

Я также просмотрел следующие веб-сайты:

Прецедент

Я загрузил код Java, структуру каталогов и XML на http://aapro.net/CatalogTest.zip

Должна быть возможность добавить что-то в мою программу, которая принимает путь к папке Test/ doctypes (папка, а не файл каталога в ней), а затем файл CatalogTest.xml должен успешно проанализировать с опцией "Validate", которую программа запрашивает. за. Другое (дорогое) программное обеспечение, поддерживающее SGML/XML, может это сделать. Средство распознавания каталога, получивший абсолютный путь к папке Test/ doctypes, должно иметь возможность следовать директиве CATALOG в файле Test/doctypes/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; Есть только несколько ситуаций, которые используют это в моей рабочей среде.

Несколько методов?

Я хотел бы попробовать более одного распознавателя и / или анализатора, либо позволить пользователю сделать выбор.

Встроенный код Java

(Также в вышеупомянутом почтовом файле)

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 ответа

Решение

Средство Apache XML Commons Resolver поддерживает как каталоги OASIS XML, так и более старый формат каталогов OASIS TR9401. См. https://xerces.apache.org/xml-commons/components/resolver/.

Чтобы включить поиск по каталогу в вашем тестовом проекте, сделайте следующее:

  1. Загрузите XML Commons Resolver с http://xerces.apache.org/mirrors.cgi.

  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);
    

Я публикую этот пример кода, потому что он включает в себя использование org.apache.xml.resolver.tools.CatalogResolver, как это предложено mzjn, и успешно работает с моим примером на http://aapro.net/CatalogTest.zip. То есть, если я запустил его и отвечаю на первое приглашение Да (я хочу проверить), а на второе - с абсолютным путем к папке Test \ doctypes, а затем просматриваю CatalogTest.xml, оно успешно следует директиве CATALOG в Test. \doctypes to "../other/forms/catalog", который, в свою очередь, указывает местоположение DTD с помощью: PUBLIC "-//Test// Формирует тип документа //EN" "forms.dtd" и сообщает мне мой топ Узел высокого уровня называется "формой".

На данный момент, я собираюсь включить это решение в мою программу XML diff. Если я обнаружу, что для обработки пути к каталогу с несколькими записями и / или обработки набора файлов catalog и 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();
        }
}
Другие вопросы по тегам