ما هي أفضل طريقة للتحقق من صحة ملف XML مقابل ملف XSD؟

StackOverflow https://stackoverflow.com/questions/15732

  •  08-06-2019
  •  | 
  •  

سؤال

أقوم بإنشاء بعض ملفات xml التي يجب أن تتوافق مع ملف xsd الذي تم إعطاؤه لي.ما هي أفضل طريقة للتحقق من مطابقتها؟

هل كانت مفيدة؟

المحلول

تدعم مكتبة وقت تشغيل Java التحقق من الصحة.آخر مرة قمت فيها بالتحقق من ذلك كان محلل Apache Xerces تحت الأغطية.ربما يجب عليك استخدام أ javax.xml.validation.Validator.

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import java.net.URL;
import org.xml.sax.SAXException;
//import java.io.File; // if you use File
import java.io.IOException;
...
URL schemaFile = new URL("http://host:port/filename.xsd");
// webapp example xsd: 
// URL schemaFile = new URL("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd");
// local file example:
// File schemaFile = new File("/location/to/localfile.xsd"); // etc.
Source xmlFile = new StreamSource(new File("web.xml"));
SchemaFactory schemaFactory = SchemaFactory
    .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
  Schema schema = schemaFactory.newSchema(schemaFile);
  Validator validator = schema.newValidator();
  validator.validate(xmlFile);
  System.out.println(xmlFile.getSystemId() + " is valid");
} catch (SAXException e) {
  System.out.println(xmlFile.getSystemId() + " is NOT valid reason:" + e);
} catch (IOException e) {}

ثابت مصنع المخطط هو السلسلة http://www.w3.org/2001/XMLSchema الذي يحدد XSDs.يتحقق الكود أعلاه من صحة واصف نشر WAR مقابل عنوان URL http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ولكن يمكنك التحقق من صحتها بسهولة مقابل ملف محلي.

يجب ألا تستخدم DOMParser للتحقق من صحة المستند (ما لم يكن هدفك هو إنشاء نموذج كائن مستند على أي حال).سيبدأ هذا في إنشاء كائنات DOM أثناء تحليل المستند - وهو ما يعد إهدارًا إذا كنت لن تستخدمها.

نصائح أخرى

وإليك كيفية القيام بذلك باستخدام زرسيس2.برنامج تعليمي لهذا، هنا (متطلب.اشتراك).

الإسناد الأصلي:منقول بشكل صارخ من هنا:

import org.apache.xerces.parsers.DOMParser;
import java.io.File;
import org.w3c.dom.Document;

public class SchemaTest {
  public static void main (String args[]) {
      File docFile = new File("memory.xml");
      try {
        DOMParser parser = new DOMParser();
        parser.setFeature("http://xml.org/sax/features/validation", true);
        parser.setProperty(
             "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", 
             "memory.xsd");
        ErrorChecker errors = new ErrorChecker();
        parser.setErrorHandler(errors);
        parser.parse("memory.xml");
     } catch (Exception e) {
        System.out.print("Problem parsing the file.");
     }
  }
}

قمنا ببناء مشروعنا باستخدام ant، حتى نتمكن من استخدام مهمة schemavalidate للتحقق من ملفات التكوين الخاصة بنا:

<schemavalidate> 
    <fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>

الآن سوف تفشل ملفات التكوين المشاغب في بناءنا!

http://ant.apache.org/manual/Tasks/schemavalidate.html

نظرًا لأن هذا سؤال شائع، سأشير إلى أنه يمكن أيضًا التحقق من صحة Java مقابل ملفات xsd "المشار إليها"، على سبيل المثال إذا كان ملف .xml نفسه يحدد XSD في الرأس، باستخدام xsi:SchemaLocation أو xsi:noNamespaceSchemaLocation (أو xsi لمساحات أسماء معينة) السابق:

<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
  ...

أو SchemaLocation (دائمًا قائمة بمساحة الاسم لتعيينات xsd)

<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:SchemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
  ...

تعمل الإجابات الأخرى هنا أيضًا، لأن ملفات .xsd "تعيين" لمساحات الأسماء المعلنة في ملف .xml، لأنها تعلن عن مساحة اسم، وإذا تطابقت مع مساحة الاسم في ملف .xml، فهذا جيد.لكن في بعض الأحيان يكون من الملائم أن تكون قادرًا على الحصول على عادة محلل...

من جافادوكس:"إذا قمت بإنشاء مخطط دون تحديد عنوان URL أو ملف أو مصدر، فإن لغة Java تقوم بإنشاء مخطط يبحث في المستند الذي يتم التحقق من صحته للعثور على المخطط الذي يجب استخدامه.على سبيل المثال:"

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();

وهذا يعمل لمساحات أسماء متعددة، وما إلى ذلك.المشكلة في هذا النهج هي أن xmlsns:xsi من المحتمل أن يكون موقعًا على الشبكة، لذلك سيخرج بشكل افتراضي ويصل إلى الشبكة مع كل عملية تحقق، وهذا ليس هو الوضع الأمثل دائمًا.

فيما يلي مثال للتحقق من صحة ملف XML مقابل أي ملفات XSD يشير إليها (حتى لو كان عليه سحبها من الشبكة):

  public static void verifyValidatesInternalXsd(String filename) throws Exception {
    InputStream xmlStream = new new FileInputStream(filename);
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setValidating(true);
    factory.setNamespaceAware(true);
    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
                 "http://www.w3.org/2001/XMLSchema");
    DocumentBuilder builder = factory.newDocumentBuilder();
    builder.setErrorHandler(new RaiseOnErrorHandler());
    builder.parse(new InputSource(xmlStream));
    xmlStream.close();
  }

  public static class RaiseOnErrorHandler implements ErrorHandler {
    public void warning(SAXParseException e) throws SAXException {
      throw new RuntimeException(e);
    }
    public void error(SAXParseException e) throws SAXException {
      throw new RuntimeException(e);
    }
    public void fatalError(SAXParseException e) throws SAXException {
      throw new RuntimeException(e);
    }
  }

يمكنك تجنب سحب ملفات XSD المشار إليها من الشبكة، على الرغم من أن ملفات xml تشير إلى عناوين url، وذلك عن طريق تحديد xsd يدويًا (راجع بعض الإجابات الأخرى هنا) أو باستخدام "كتالوج XML" محلل النمط.ويبدو أن الربيع أيضاً يمكن أن يعترض يطلب عنوان URL خدمة الملفات المحلية لعمليات التحقق من الصحة.أو يمكنك تعيين الخاص بك عن طريق setResourceResolver, ، السابق:

Source xmlFile = new StreamSource(xmlFileLocation);
SchemaFactory schemaFactory = SchemaFactory
                                .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
Validator validator = schema.newValidator();
validator.setResourceResolver(new LSResourceResolver() {
  @Override
  public LSInput resolveResource(String type, String namespaceURI,
                                 String publicId, String systemId, String baseURI) {
    InputSource is = new InputSource(
                           getClass().getResourceAsStream(
                          "some_local_file_in_the_jar.xsd"));
                          // or lookup by URI, etc...
    return new Input(is); // for class Input see 
                          // https://stackoverflow.com/a/2342859/32453
  }
});
validator.validate(xmlFile);

أنظر أيضا هنا لتعليم آخر.

أعتقد أن الإعداد الافتراضي هو استخدام تحليل DOM، ويمكنك القيام بشيء مماثل باستخدام محلل SAX الذي يتم التحقق من صحته أيضًا saxReader.setEntityResolver(your_resolver_here);

باستخدام Java 7، يمكنك متابعة الوثائق المتوفرة في حزمة الوصف.

// parse an XML document into a DOM tree
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = parser.parse(new File("instance.xml"));

// create a SchemaFactory capable of understanding WXS schemas
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

// load a WXS schema, represented by a Schema instance
Source schemaFile = new StreamSource(new File("mySchema.xsd"));
Schema schema = factory.newSchema(schemaFile);

// create a Validator instance, which can be used to validate an instance document
Validator validator = schema.newValidator();

// validate the DOM tree
try {
    validator.validate(new DOMSource(document));
} catch (SAXException e) {
    // instance document is invalid!
}

إذا كان لديك جهاز Linux، فيمكنك استخدام أداة سطر الأوامر المجانية SAXCount.لقد وجدت هذا مفيدا جدا.

SAXCount -f -s -n my.xml

يتم التحقق من صحته ضد dtd وxsd.5s لملف 50MB.

في ضغط دبيان، يوجد في الحزمة "libxerces-c-samples".

يجب أن يكون تعريف dtd وxsd في ملف XML!لا يمكنك تكوينها بشكل منفصل.

إجابة واحدة أخرى:منذ قلت أنك بحاجة إلى التحقق من صحة الملفات أنت توليد (الكتابة)، قد ترغب في التحقق من صحة المحتوى أثناء الكتابة، بدلاً من الكتابة أولاً، ثم إعادة القراءة للتحقق من صحته.ربما يمكنك القيام بذلك باستخدام JDK API للتحقق من صحة Xml، إذا كنت تستخدم كاتبًا يستند إلى SAX:إذا كان الأمر كذلك، ما عليك سوى ربط أداة التحقق عن طريق استدعاء "Validator.validate(source, result)"، حيث يأتي المصدر من كاتبك، والنتيجة هي المكان الذي يجب أن تذهب إليه المخرجات.

وبدلاً من ذلك، إذا كنت تستخدم Stax لكتابة المحتوى (أو مكتبة تستخدم Stax أو يمكنها استخدامه)، وودستوكس يمكنه أيضًا دعم التحقق من الصحة بشكل مباشر عند استخدام XMLStreamWriter.وهنا أ دخول بلوق يوضح كيف يتم ذلك:

إذا كنت تقوم بإنشاء ملفات XML برمجيًا، فقد ترغب في الاطلاع على ملف XMLBeans مكتبة.باستخدام أداة سطر الأوامر، سيقوم XMLBeans تلقائيًا بإنشاء وتعبئة مجموعة من كائنات Java استنادًا إلى XSD.يمكنك بعد ذلك استخدام هذه الكائنات لإنشاء مستند XML استنادًا إلى هذا المخطط.

يحتوي على دعم مدمج للتحقق من صحة المخطط، ويمكنه تحويل كائنات Java إلى مستند XML والعكس.

الخروع و جاكسب هي مكتبات Java أخرى تخدم غرضًا مشابهًا لـ XMLBeans.

هل تبحث عن أداة أو مكتبة؟

وفيما يتعلق بالمكتبات، فإن المعيار الفعلي هو إلى حد كبير زرسيس2 الذي لديه كليهما سي ++ و جافا الإصدارات.

كن حذرًا على الرغم من أنه حل ثقيل الوزن.ولكن مرة أخرى، يعد التحقق من صحة XML مقابل ملفات XSD مشكلة ثقيلة الوزن إلى حد ما.

أما بالنسبة للأداة للقيام بذلك نيابةً عنك، XMLFox يبدو أنه حل مجاني لائق، لكن لا يمكنني الجزم بعدم استخدامه شخصيًا.

مع JAXB، يمكنك استخدام الكود أدناه:

    @Test
public void testCheckXmlIsValidAgainstSchema() {
    logger.info("Validating an XML file against the latest schema...");

    MyValidationEventCollector vec = new MyValidationEventCollector();

    validateXmlAgainstSchema(vec, inputXmlFileName, inputXmlSchemaName, inputXmlRootClass);

    assertThat(vec.getValidationErrors().isEmpty(), is(expectedValidationResult));
}

private void validateXmlAgainstSchema(final MyValidationEventCollector vec, final String xmlFileName, final String xsdSchemaName, final Class<?> rootClass) {
    try (InputStream xmlFileIs = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFileName);) {
        final JAXBContext jContext = JAXBContext.newInstance(rootClass);
        // Unmarshal the data from InputStream
        final Unmarshaller unmarshaller = jContext.createUnmarshaller();

        final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final InputStream schemaAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaName);
        unmarshaller.setSchema(sf.newSchema(new StreamSource(schemaAsStream)));

        unmarshaller.setEventHandler(vec);

        unmarshaller.unmarshal(new StreamSource(xmlFileIs), rootClass).getValue(); // The Document class is the root object in the XML file you want to validate

        for (String validationError : vec.getValidationErrors()) {
            logger.trace(validationError);
        }
    } catch (final Exception e) {
        logger.error("The validation of the XML file " + xmlFileName + " failed: ", e);
    }
}

class MyValidationEventCollector implements ValidationEventHandler {
    private final List<String> validationErrors;

    public MyValidationEventCollector() {
        validationErrors = new ArrayList<>();
    }

    public List<String> getValidationErrors() {
        return Collections.unmodifiableList(validationErrors);
    }

    @Override
    public boolean handleEvent(final ValidationEvent event) {
        String pattern = "line {0}, column {1}, error message {2}";
        String errorMessage = MessageFormat.format(pattern, event.getLocator().getLineNumber(), event.getLocator().getColumnNumber(),
                event.getMessage());
        if (event.getSeverity() == ValidationEvent.FATAL_ERROR) {
            validationErrors.add(errorMessage);
        }
        return true; // you collect the validation errors in a List and handle them later
    }
}

التحقق من صحة ضد المخططات عبر الإنترنت

Source xmlFile = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("your.xml"));
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(Thread.currentThread().getContextClassLoader().getResource("your.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlFile);

التحقق من صحة ضد المخططات المحلية

التحقق من صحة XML دون اتصال مع Java

اضطررت إلى التحقق من صحة XML مقابل XSD مرة واحدة فقط، لذلك قمت بتجربة XMLFox.لقد وجدت أن الأمر محير وغريب للغاية.يبدو أن تعليمات المساعدة لا تتطابق مع الواجهة.

انتهى بي الأمر باستخدام LiquidXML Studio 2008 (الإصدار 6) الذي كان أسهل في الاستخدام وأكثر دراية على الفور (واجهة المستخدم مشابهة جدًا لـ Visual Basic 2008 Express، الذي أستخدمه كثيرًا).العيب:إمكانية التحقق من الصحة غير متوفرة في الإصدار المجاني، لذلك اضطررت إلى استخدام الإصدار التجريبي لمدة 30 يومًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top