Проверка XML на соответствие XSD в Java/получение расположения схемы

Как можно проверить файл XML с помощью XSD в Java? Мы не знаем схему заранее. Я хотел бы иметь возможность получить schemaLocation, загрузить XSD, кэшировать его, а затем выполнить фактическую проверку.

Проблема в том, что с классами javax.xml.parsers.DocumentBuilder/DocumentBuilderFactory я не могу заранее получить schemaLocation. В чем хитрость для этого? Какие классы я должен изучить?

Возможно, есть более подходящий API, который я могу использовать? Вся проблема в том, что нам нужно выполнять динамическую проверку без (обязательно) локального наличия XSD.

Как можно получить URL-адрес schemaLocation, определенный в файле XSD?

Я знаю, что вы можете установить функции/атрибуты, но это другое дело. Сначала мне нужно получить schemaLocation из XSD.

Пожалуйста, порекомендуйте!


person carlspring    schedule 01.02.2012    source источник


Ответы (1)


Учитывая, что вы используете Xerces (или JDK по умолчанию), пытались ли вы установить для этой функции значение true на заводе: http://apache.org/xml/features/validation/schema. Существуют и другие функции, с которыми вы можете поиграть в отношении схем: http://xerces.apache.org/xerces2-j/features.html

ОБНОВЛЕНИЕ 2 (для кэширования):

Реализуйте org.w3c.dom.ls.LSResourceResolver и установите его на SchemaFactory с помощью метода setResourceResolver. Этот распознаватель либо получит схему из кеша, либо извлечет ее из любого места, на которое ссылается местоположение.

ОБНОВЛЕНИЕ 3:

Пример LSResourceresolver (который, я думаю, станет для вас хорошей отправной точкой):

/**
 * Resolves resources from a base URL
 */
public class URLBasedResourceResolver implements LSResourceResolver {

private static final Logger log = LoggerFactory
        .getLogger(URLBasedResourceResolver.class);

private final URI base;

private final Map<URI, String> nsmap;

public URLBasedResourceResolver(URL base, Map<URI, String> nsmap)
        throws URISyntaxException {
    super();
    this.base = base.toURI();
    this.nsmap = nsmap;
}

@Override
public LSInput resolveResource(String type, String namespaceURI,
        String publicId, String systemId, String baseURI) {
    if (log.isDebugEnabled()) {
        String msg = String
                .format("Resolve: type=%s, ns=%s, publicId=%s, systemId=%s, baseUri=%s.",
                        type, namespaceURI, publicId, systemId, baseURI);
        log.debug(msg);
    }
    if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
        if (namespaceURI != null) {
            try {
                URI ns = new URI(namespaceURI);
                if (nsmap.containsKey(ns))
                    return new MyLSInput(base.resolve(nsmap.get(ns)));
            } catch (URISyntaxException e) {
                // ok
            }
        }
    }
    return null;
}

}

Реализация MyLSInput действительно скучна:

class MyLSInput implements LSInput {

private final URI url;

public MyLSInput(URI url) {
    super();
    this.url = url;
}

@Override
public Reader getCharacterStream() {
    return null;
}

@Override
public void setCharacterStream(Reader characterStream) {

}

@Override
public InputStream getByteStream() {
    return null;
}

@Override
public void setByteStream(InputStream byteStream) {

}

@Override
public String getStringData() {
    return null;
}

@Override
public void setStringData(String stringData) {

}

@Override
public String getSystemId() {
    return url.toASCIIString();
}

@Override
public void setSystemId(String systemId) {
}

@Override
public String getPublicId() {
    return null;
}

@Override
public void setPublicId(String publicId) {
}

@Override
public String getBaseURI() {
    return null;
}

@Override
public void setBaseURI(String baseURI) {

}

@Override
public String getEncoding() {
    return null;
}

@Override
public void setEncoding(String encoding) {

}

@Override
public boolean getCertifiedText() {
    return false;
}

@Override
public void setCertifiedText(boolean certifiedText) {

}

}
person forty-two    schedule 01.02.2012
comment
Что касается первой ссылки - я использую xerces: 2.10.0 как отдельную зависимость Maven вне JDK. Вторая ссылка не работает. Я не против использования другого API вместе. - person carlspring; 01.02.2012
comment
Да, хотя это действительно правильно, у меня все еще нет местоположения схемы, поэтому я не могу ее кэшировать, и мне нужно реализовать кэширование. Поэтому мне действительно нужно сначала заполучить schemaLocation. - person carlspring; 01.02.2012
comment
Извините, невнимательно прочитал вопрос. Смотрите второе обновление. - person forty-two; 01.02.2012
comment
Я думаю, что это шаг в правильном направлении. Может быть, у вас есть пример того, как правильно это использовать? - person carlspring; 01.02.2012
comment
Извините, но я, кажется, не понимаю этого. Вы можете установить ResourceResolver для SchemaFactory. Однако SchemaFactory даст вам экземпляр Schema, который вы сможете использовать, только если знаете schemaLocation. У меня нет schemaLocation заранее, и я хотел бы получить его из XML-файла. Что мне здесь не хватает? - person carlspring; 02.02.2012
comment
Спасибо! Разобрался с небольшой помощью! :) Ваш ответ действительно то, что мне нужно. - person carlspring; 02.02.2012