Валидатор Jing RelaxNG и библиотека пользовательских типов данных из кода Java

Прочитав это, я попытался реализовать пользовательский тип данных для использоваться валидатором XML RelaxNG (Jing). Я успешно запустил пример реализации, предоставленный Jing (они называют его datatype-sample) через командную строку, но мне не удается сделать это из java-кода.

Из командной строки (окна):

> set CLASSPATH=path\to\jing-20091111\bin\jing.jar;path\to\jing-20091111\sample\datatype\datatype-sample.jar
> cd path\to\jing-20091111\sample\datatype
> java com.thaiopensource.relaxng.util.Driver datatype-sample.rng valid.xml

Проверка прошла без проблем. Но теперь я пытаюсь использовать ту же библиотеку типов данных из следующего кода Java:

package rngdatatype;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.SAXException;

public class Main {

    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException, SAXException, IOException {
        // make sure our jars are on classpath
        System.out.println("Classpath: " + System.getProperty("java.class.path"));

        // args
        String rng = args[0];
        String xml = args[1];
        File rngFile = new File(rng);
        File xmlFile = new File(xml);

        // setup rng validator through JAXP
        System.setProperty(SchemaFactory.class.getName() + ":" + XMLConstants.RELAXNG_NS_URI, "com.thaiopensource.relaxng.jaxp.XMLSyntaxSchemaFactory");
        SchemaFactory rngSchemaFactory = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);

        // obtain a schema object
        InputStreamReader rngReader = new InputStreamReader(new FileInputStream(rngFile), "UTF-8");
        Schema schema = rngSchemaFactory.newSchema(new StreamSource(rngReader));

        // validate using schema based validator
        Validator validator = schema.newValidator();
        InputStreamReader xmlReader = new InputStreamReader(new FileInputStream(xmlFile), "UTF-8");
        validator.validate(new StreamSource(xmlReader));
    }
}

Первый аргумент — это путь к файлу со следующим содержимым:

<element name="balancedString"
   xmlns="http://relaxng.org/ns/structure/1.0"
   datatypeLibrary="http://www.thaiopensource.com/relaxng/datatypes/sample">
  <data type="balancedString"/>
</element>

И вторым аргументом является путь к файлу со следующим содержимым:

<balancedString>foo(bar(baz))</balancedString>

Что дает мне следующий вывод:

Classpath: path\to\RNGDataType\lib\datatype-sample.jar;path\to\RNGDataType\lib\jing.jar;path\to\RNGDataType\build\classes;path\to\RNGDataType\src
Exception in thread "main" org.xml.sax.SAXParseException: datatype library "http://www.thaiopensource.com/relaxng/datatypes/sample" not recognized
...

Это ясно указывает на то, что тип данных не может быть разрешен. Насколько я могу судить, единственное требование для этого (иметь как jing.jar, так и datatype-sample.jar в пути к классам) выполнено. Так что я делаю неправильно?

P.S: чтобы приведенный выше код работал, вы должны поместить jing.jar и datatype-sample.jar в свой путь к классам И предоставить ему аргументы, где первый - это путь к datatype-sample.rng, а второй - путь к valid.xml или invalid.xml. Все они распространяются вместе с Jing. .

Edit1: указанная выше программа также не работает за пределами моей IDE при запуске в виде JAR (java -jar) с правильным файлом MANIFEST.MF. Также не работает, если путь к классам задан вручную (java -classpath). Поэтому я подозреваю, что что-то не так с фактическим кодом.


person predi    schedule 31.05.2012    source источник


Ответы (2)


Похоже, что использование пользовательских библиотек типов данных через Jing через JAXP API каким-то образом не работает. Это не работает, хотя должно. Возможно, нужно где-то задать какие-то дополнительные свойства, а я просто об этом не знаю.

Поэтому я думаю, что нашел обходной путь, подражая com.thaiopensource.relaxng.util.Driver Jing и, следовательно, используя собственный API Jing для выполнения проверки. Обратите внимание, что это ограничивает ваш код, поэтому он работает только с Jing.

package rngdatatype;

import com.thaiopensource.validate.SchemaReader;
import com.thaiopensource.validate.ValidationDriver;
import com.thaiopensource.validate.auto.AutoSchemaReader;
import java.io.File;
import java.io.IOException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class JingApi {

    public static void main(String[] args) throws SAXException, IOException {
        String rng = args[0];
        String xml = args[1];
        File rngFile = new File(rng);
        File xmlFile = new File(xml);

        SchemaReader sr = new AutoSchemaReader();
        ValidationDriver driver = new ValidationDriver(sr);
        InputSource inRng = ValidationDriver.fileInputSource(rngFile);
        inRng.setEncoding("UTF-8");
        driver.loadSchema(inRng);
        InputSource inXml = ValidationDriver.fileInputSource(xmlFile);
        inXml.setEncoding("UTF-8");
        driver.validate(inXml);
    }
}

Это позволяет вам проверять XML-файлы из кода Java на основе схемы RNG, в которой используются библиотеки пользовательских типов данных. Обратите внимание, что класс Diver, о котором я упоминал ранее, нельзя использовать напрямую.

Вышеприведенная программа использует тот же путь к классам и аргументы, что и пример в моем собственном вопросе.

Изменить1 ------------------------------------------------------------< /сильный>

Немного повозившись, я нашел свойство, которое необходимо установить, чтобы мой пример JAXP работал вместе с Jing при использовании пользовательских библиотек типов данных. Просто добавьте следующую строку после получения экземпляра SchemaFactory:

rngSchemaFactory.setProperty("http://relaxng.org/properties/datatype-library-factory", new org.relaxng.datatype.helpers.DatatypeLibraryLoader());

Это гораздо более элегантное решение, чем использование собственного API Jing.

/Edit1 -----------------------------------------------------------< /сильный>

person predi    schedule 08.06.2012

Ваш JAR-файл должен включать дополнительные метаданные в виде файла META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory, который должен содержать имя класса, реализующего интерфейс org.relaxng.datatype.DatatypeLibraryFactory.

person alexbrn    schedule 01.06.2012
comment
Он уже делает это. datatype-sample.jar, который, как объяснено, является примером реализации библиотеки типов данных от разработчиков Jing, имеет то, что вы предлагаете. В противном случае запуск примера из командной строки также не сработает. - person predi; 01.06.2012