Автономная проверка XML с помощью Java

Мне нужно выяснить, как проверять мои файлы XML с помощью автономной схемы. После осмотра в течение нескольких дней я смог найти, что мне нужно было иметь внутреннюю ссылку на схему. Мне нужно было найти их, загрузить их и изменить ссылку на путь локальной системы. То, что я не смог найти, это как именно это сделать. Где и как я могу изменить ссылку на точку внутри, а не снаружи? Каков наилучший способ загрузки схем?

3 ответа

Есть три способа сделать это. Общим для всех является то, что вам нужна локальная копия документа (ов) схемы. Я предполагаю, что экземпляры документов в настоящее время используют xsi:schemaLocation и / или xsi:noNamespaceSchemaLocation, чтобы указывать на местоположение, содержащее документ (ы) схемы в Интернете.

(a) Измените ваши документы экземпляра, чтобы они ссылались на локальную копию документов схемы. Это обычно неудобно.

(б) Перенаправить ссылки так, чтобы запрос на удаленный файл был перенаправлен в локальный файл. Способ установки зависит от того, какой валидатор схемы вы используете и как вы его вызываете.

(c) Скажите обработчику схемы игнорировать значения xsi:schemaLocation и xsi:noNamespaceSchemaLocation и вместо этого выполнить проверку по схеме, предоставленной вами, с помощью API вызова процессора схемы. Опять же, детали зависят от того, какой процессор схемы вы используете.

Мой предпочтительный подход (с): хотя бы потому, что когда вы проверяете исходный документ, то по определению вы не полностью ему доверяете - так почему вы должны доверять ему, чтобы он содержал правильный атрибут xsi:schemaLocation?

Вы можете установить собственную реализацию ResourceResolver и LSInput для SchemaFactory, чтобы при вызове LSInput.getCharacterStream() схема получалась из локального пути.

Я написал дополнительный класс для проверки в автономном режиме. Вы можете назвать это как

new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/",
                        "schemas/datacite/kernel-4.1/");

Два InputStream проходят. Один для xml, один для схемы. BaseUrl и localPath (относительно classpath) передаются в качестве третьего и четвертого параметра. Последние два параметра используются валидатором для поиска дополнительных схем локально по localPath или относительно предоставленного baseUrl.

Я проверил с набором схем и примеров из https://schema.datacite.org/meta/kernel-4.1/.

Полный пример:

 @Test
 public void validate4() throws Exception {
        InputStream xmlStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(
                        "schemas/datacite/kernel-4.1/example/datacite-example-complicated-v4.1.xml");
        InputStream schemaStream = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream("schemas/datacite/kernel-4.1/metadata.xsd");
        new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/",
                        "schemas/datacite/kernel-4.1/");
 }

XmlSchemaValidator проверит xml по схеме и будет искать локально найденные схемы. Он использует ResourceResolver для переопределения стандартного поведения и локального поиска.

public class XmlSchemaValidator {
    /**
     * @param xmlStream
     *            xml data as a stream
     * @param schemaStream
     *            schema as a stream
     * @param baseUri
     *            to search for relative pathes on the web
     * @param localPath
     *            to search for schemas on a local directory
     * @throws SAXException
     *             if validation fails
     * @throws IOException
     *             not further specified
     */
    public void validate(InputStream xmlStream, InputStream schemaStream, String baseUri, String localPath)
                    throws SAXException, IOException {
        Source xmlFile = new StreamSource(xmlStream);
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        factory.setResourceResolver((type, namespaceURI, publicId, systemId, baseURI) -> {
            LSInput input = new DOMInputImpl();
            input.setPublicId(publicId);
            input.setSystemId(systemId);
            input.setBaseURI(baseUri);
            input.setCharacterStream(new InputStreamReader(
                            getSchemaAsStream(input.getSystemId(), input.getBaseURI(), localPath)));
            return input;
        });
        Schema schema = factory.newSchema(new StreamSource(schemaStream));
        javax.xml.validation.Validator validator = schema.newValidator();
        validator.validate(xmlFile);
    }

    private InputStream getSchemaAsStream(String systemId, String baseUri, String localPath) {
        InputStream in = getSchemaFromClasspath(systemId, localPath);
        // You could just return in; , if you are sure that everything is on
        // your machine. Here I call getSchemaFromWeb as last resort.
        return in == null ? getSchemaFromWeb(baseUri, systemId) : in;
    }

    private InputStream getSchemaFromClasspath(String systemId, String localPath) {
        System.out.println("Try to get stuff from localdir: " + localPath + systemId);
        return Thread.currentThread().getContextClassLoader().getResourceAsStream(localPath + systemId);
    }

    /*
     * You can leave out the webstuff if you are sure that everything is
     * available on your machine
     */
    private InputStream getSchemaFromWeb(String baseUri, String systemId) {
        try {
            URI uri = new URI(systemId);
            if (uri.isAbsolute()) {
                System.out.println("Get stuff from web: " + systemId);
                return urlToInputStream(uri.toURL(), "text/xml");
            }
            System.out.println("Get stuff from web: Host: " + baseUri + " Path: " + systemId);
            return getSchemaRelativeToBaseUri(baseUri, systemId);
        } catch (Exception e) {
            // maybe the systemId is not a valid URI or
            // the web has nothing to offer under this address
        }
        return null;
    }

    private InputStream urlToInputStream(URL url, String accept) {
        HttpURLConnection con = null;
        InputStream inputStream = null;
        try {
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(15000);
            con.setRequestProperty("User-Agent", "Name of my application.");
            con.setReadTimeout(15000);
            con.setRequestProperty("Accept", accept);
            con.connect();
            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
                            || responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == 307
                            || responseCode == 303) {
                String redirectUrl = con.getHeaderField("Location");
                try {
                    URL newUrl = new URL(redirectUrl);
                    return urlToInputStream(newUrl, accept);
                } catch (MalformedURLException e) {
                    URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
                    return urlToInputStream(newUrl, accept);
                }
            }
            inputStream = con.getInputStream();
            return inputStream;
        } catch (SocketTimeoutException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private InputStream getSchemaRelativeToBaseUri(String baseUri, String systemId) {
        try {
            URL url = new URL(baseUri + systemId);
            return urlToInputStream(url, "text/xml");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

печать

Try to get stuff from localdir: schemas/datacite/kernel-4.1/http://www.w3.org/2009/01/xml.xsd
Get stuff from web: http://www.w3.org/2009/01/xml.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-titleType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-contributorType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-dateType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-resourceType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relationType-v4.1.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relatedIdentifierType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-funderIdentifierType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-descriptionType-v4.xsd
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-nameType-v4.1.xsd

Печать показывает, что валидатор был в состоянии проверять набор локальных схем. Только http://www.w3.org/2009/01/xml.xsd не был доступен локально и поэтому был получен из Интернета.

XmlValidate - это простой, но мощный инструмент командной строки, который может выполнять автономную проверку одного или нескольких файлов XML по целевым схемам. Он может сканировать локальные файлы XML по имени файла, каталогу или URL.

XmlValidate автоматически добавляет schemaLocation на основе пространства имен схемы и файла конфигурации, который сопоставляется с локальным файлом. Инструмент будет проверять соответствие любой XML-схеме в файле конфигурации.

Вот примерные сопоставления пространства имен для целевой схемы в файле конфигурации:

http://www.opengis.net/kml/2.2=${XV_HOME}/schemas/kml22.xsd
http://appengine.google.com/ns/1.0=C:/xml/appengine-web.xsd
urn:oasis:names:tc:ciq:xsdschema:xAL:2.0=C:/xml/xAL.xsd

Обратите внимание, что маркер ${XV_HOME}, приведенный выше, является просто псевдонимом для каталога верхнего уровня, из которого выполняется XmlValidate. Расположение также может быть полным путем к файлу.

XmlValidate - это проект с открытым исходным кодом (доступен исходный код), который работает с Java Runtime Environment (JRE). Прилагаемое приложение (Java jar, примеры и т. Д.) Можно скачать здесь.

Если XmlValidate запускается в пакетном режиме для нескольких файлов XML, он предоставит сводку результатов проверки.

Errors: 17  Warnings: 0  Files: 11  Time: 1506 ms
Valid files 8/11 (73%)
Другие вопросы по тегам