Могу ли я проверить файл XML на соответствие фрагменту XSD в Java

Могу ли я проверить файл XML на соответствие фрагменту xsd? Например, у меня есть такой XML:

<tag1>
    <xx>...</xx>
</tag1>

И XSD вроде:

<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="envTeste">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="tag" minOccurs="1" maxOccurs="1">
          <xsd:simpleType>
            <xsd:restriction base="xsd:int">
              <xsd:totalDigits value="1" />
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
        <xsd:element name="tag1" minOccurs="1" maxOccurs="1">
          <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:pattern value="^\d{1,15}$"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
............................

Я хочу использовать только фрагмент "name=tag1" для проверки моего xml. Это возможно? Используете JAXB?

Большое спасибо.


person fdam    schedule 11.08.2014    source источник
comment
Почему вы хотите проверить только фрагмент? Схема — это то, что определяет, что ваш XML действителен, поэтому, если в остальной части XML-разметки отсутствуют необходимые элементы, как ее можно считать действительной? Я бы подумал, что вы могли бы добиться чего-то более близкого к тому, что вы хотите, определив схему по частям, а не в одном файле и проверив ее по отдельным частям, хотя я думаю, что это противоречит основной цели иметь схему...   -  person Ryan J    schedule 11.08.2014
comment
XSD является частью проприетарной среды, и я понятия не имею, почему они делают один xsd для проверки нескольких xml. Мой последний вариант - определить этот xsd по частям.   -  person fdam    schedule 11.08.2014


Ответы (4)


Нет, это невозможно с JAXB, и я не думаю, что какой-либо другой инструмент сможет выполнять такие частичные проверки, учитывая текущую схему XML и данные XML, как показано.

Во-первых, показанный вами XML не соответствует части схемы XML <xsd:element name="tag1"...>>. Так что все равно не пройдет проверку.

Во-вторых, если предположить, что код XML-схемы и данные XML совпадают, вы можете подумать о заключении данных XML в элемент <envTeste>, но тогда проверка не будет успешной из-за отсутствия элемента <tag>.

НО вы можете написать (правильный и соответствующий!) элемент <tag1> в качестве элемента XML-схемы верхнего уровня и ссылаться на него из <envTeste>. Затем XML-документ, состоящий из <tag1>, может быть рассортирован, при этом файл схемы XML будет передан демаршаллеру.

Другим вариантом может быть (довольно простой) XSLT для создания XML-схемы из «интересных» элементов, установки их в качестве элементов верхнего уровня — при условии, что схема не слишком сложна. Ненадежный, но может быть жизнеспособным.

person laune    schedule 11.08.2014
comment
Учтите, что соответствующий xml правильный, приведенный выше просто пример, это не моя проблема. Что я действительно хочу знать, так это то, возможно ли это или нет, я делаю эту проверку, просто используя фрагмент. Потому что xsd является проприетарным, а xmls я получаю через restful ws (тоже проприетарный). Я не хочу разделять этот xsd на фрагменты, только если у меня нет возможности. - person fdam; 11.08.2014
comment
Я придумал другой вариант. В противном случае это упаковка или исправление схемы. - person laune; 11.08.2014

Поскольку я неправильно прочитал ваш пост в первый раз, я удалил свой ответ и создал новый:

Если исходная схема содержит поддерево, которое вы хотите использовать для проверки, вы можете найти верхний узел поддерева с помощью выражения XPath, например f.e. //@*:name = 'tag1' или //@name = 'tag1', если вы не используете определения пространств имен.

Node node = (Node)xpath.evaluate(xpathExpression, originSchemaDocument, XPathConstants.NODE);

По сути, вы хотите вызвать SchemaFactory.newSchema(Source) для создания схемы, которую можно использовать для проверки. Поэтому, вероятно, наиболее удобным способом является создание DOMSИсточник.

Кроме того, этот источник может быть создан с использованием нового Document< /a>, где вы, вероятно, можете использовать importNode, чтобы скопировать ранее извлеченное поддерево в новую "схему". Кроме того, вам необходимо добавить определение схемы в документ, который вы создаете, либо вручную, либо путем копирования из исходной схемы, иначе вы не получите действительную схему.

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

person Roman Vottner    schedule 11.08.2014

Я думаю, проблема заключается в том, что авторы схемы решили сделать tag1 объявлением локального элемента, а не объявлением глобального элемента. Если бы это было глобальное объявление, вы могли бы проверить отдельно стоящий элемент tag1 (люди иногда жалуются на эту функцию XSD, но в вашем случае это то, что вам нужно), но поскольку это локальное объявление, оно доступно только в контексте его родительского элемента envTeste. Более того, envTeste требует присутствия других родственных элементов, поэтому вы не можете просто обернуть свой tag1 в envTeste перед проверкой.

В этом конкретном случае ваше объявление локального элемента не имеет зависимостей от других компонентов схемы, и нет задействованных пространств имен, поэтому вы можете извлечь его в текстовом виде, чтобы сформировать новую схему, как предложили другие. Однако в общем случае это не сработает. Схема не предназначена для использования так, как вы пытаетесь ее использовать.

person Michael Kay    schedule 12.08.2014

Я решил свою проблему другим способом.

Сначала я создал объекты Java, используя xmlbeans:

Конфигурация ANT:

build.properties

xbean-dest-file = ./lib/sat-beans-1.0.jar # my generated jar
xbean-class-name = org.apache.xmlbeans.impl.tool.XMLBean
xbean-class-path = ./lib/xbean.jar:./lib/jsr173_1.0_api.jar #dependencies

build.xml

<target name="sat-beans">
    <mkdir  dir="${xbean-gen}"/>
    <mkdir  dir="${xbean-classes}"/>
    <taskdef name="xmlbean" classname="${xbean-class-name}" classpath="${xbean-class-path}"/>
    <xmlbean schema="./xsd/CfeTeste_0006.xsd" classgendir="${xbean-classes}" 
            srcgendir="${xbean-gen}"  
            destfile="${xbean-dest-file}" 
            classpath="${xbean-class-path}" />
</target>

Затем я импортировал эту банку в свой проект и сделал проверку следующим образом:

public void validate(String xml) {

    try {

        List<XmlValidationError> errors = new ArrayList<XmlValidationError>();
        EnvTesteDocument envTesteDocument = EnvTesteDocument.Factory.parse(xml);

        XmlOptions voptions = new XmlOptions();
        voptions.setValidateOnSet();
        voptions.setErrorListener(errors);

        if (envTesteDocument.getEnvTeste().getCFe().validate(voptions)) {
            return;
        }

        for (XmlValidationError error : errors) {
            ...
        }


    } catch (XMLInvalidException e) {}

}

Спасибо за все!

person fdam    schedule 12.08.2014