XSD 파일에 대해 XML 파일의 유효성을 검사하는 가장 좋은 방법은 무엇입니까?


263

나에게 주어진 xsd 파일을 준수 해야하는 일부 XML 파일을 생성 중입니다. 그것들이 일치하는지 확인하는 가장 좋은 방법은 무엇입니까?

답변:


336

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/XMLSchemaXSD를 정의 하는 문자열 입니다. 위의 코드는 URL에 대해 WAR 배치 디스크립터를 유효성 검증 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd하지만 로컬 파일에 대해서도 쉽게 유효성을 검증 할 수 있습니다.

문서 오브젝트 모델을 작성하는 것이 아니라면 DOMParser를 사용하여 문서를 유효성 검증하지 않아야합니다. 문서를 구문 분석 할 때 DOM 객체를 생성하기 시작합니다. 사용하지 않을 경우 낭비입니다.


이 예제에서 DOM 또는 SAX 파서를 사용하고 있습니까? 어느쪽에 대한 참조를 볼 수 없으므로 어떤 파서를 사용하고 있는지 어떻게 알 수 있습니까?
ziggy

1
@ziggy-이것은 JAXP 구현 의 구현 세부 사항입니다 . Sun의 JDK 6은 SAX 파서를 StreamSource 와 함께 사용 합니다 . 이 경우 JAXP 구현 합법적으로 DOM 파서를 사용할 있지만 그럴 이유가 없습니다. 유효성 검사를 위해 DOM 구문 분석기를 명시 적으로 사용하는 경우 DOM 트리를 인스턴스화해야합니다.
McDowell

위의 오류 처리기를 어떻게 사용합니까? ErrorHandler를 작성하고 유효성 검증기와 연관시키는 경우입니까? 이 SO 질문의 예에서와 같이, 즉 validator.SetErrorHandler () stackoverflow.com/questions/4864681/... ?
ziggy

execptions은 안 단지 execptional 상황 및 사용할 수 없습니다 제어 흐름을 위해?
mike

이 코드는 치명적인 오류 만 포착하지 않습니까? 치명적이지 않은 (예 : 구조적이지 않은) 치명을 잡으려면 ErrorHandler를 사용해야한다고 생각합니다.
matt forsythe

25

Xerces2 사용하는 방법은 다음과 같습니다 . 이에 대한 튜토리얼은 여기 (요청 가입)입니다.

원래 귀속 : 여기 에서 뻔뻔스럽게 복사 :

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.");
     }
  }
}

9
SAX 파서는보다 효율적이다-DOM 파서는 DOM 객체를 생성한다; 이 경우 낭비되는 작업.
McDowell

문제는 XSD에 대해 XML의 유효성을 검사하는 것입니다. 이 답변에서 더 나아가서 필요하지 않은 Parser 객체를 얻습니다.
Weslor

"ErrorChecker를 유형으로 해석 할 수 없습니다."
Alex

20

ant를 사용하여 프로젝트를 빌드하므로 schemavalidate 태스크를 사용하여 구성 파일을 확인할 수 있습니다.

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

이제 나쁜 구성 파일이 빌드에 실패합니다!

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


13

이것은 대중적인 질문이므로 java는 .xml 파일 자체가 헤더에 XSD를 지정 xsi:SchemaLocation하거나 xsi:noNamespaceSchemaLocation(또는 특정 네임 스페이스의 경우 xsi) ex :

<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 파일의 네임 스페이스와 일치하면 좋습니다. 그러나 때로는 맞춤형 리졸버 를 가질 수있는 것이 편리합니다 ...

javadocs에서 : "URL, 파일 또는 소스를 지정하지 않고 스키마를 작성하는 경우 Java 언어는 유효성을 검사 할 문서를 찾아서 사용해야하는 스키마를 찾습니다. 예를 들면 다음과 같습니다."

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

이것은 여러 네임 스페이스 등에서 작동합니다.이 방법의 문제점 xmlsns:xsi은 네트워크 위치 일 가능성이 있기 때문에 기본적으로 항상 최적의 것은 아니지만 모든 유효성 검사를 수행하여 네트워크를 종료합니다.

다음은 참조하는 모든 XSD에 대해 XML 파일의 유효성을 검사하는 예입니다 (네트워크에서 파일을 가져와야하는 경우에도).

  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);
    }
  }

xml 파일이 url을 참조하더라도 xsd를 수동으로 지정하거나 (여기서 다른 답변 참조) "XML catalog" 스타일 resolver 를 사용하여 네트워크에서 참조 된 XSD를 가져 오는 것을 피할 수 있습니다 . Spring은 분명히 유효성 검사를 위해 로컬 파일을 제공하기 위해 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);


작동하지 않습니다. schemaResource에 설정되어 있지 않으면 resolveResource () 메소드가 호출되지 않습니다.
tomasb

던노, 나를 위해 일해 당신이 그것을 통해 그것을 설정하고 있는지 확인하십시오. setResourceResolver그 밖의 새로운 질문이있을 수도 있습니다.
rogerdpack

6

Java 7을 사용하면 패키지 설명에 제공된 설명서를 따를 수 있습니다 .

// 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 StreamSource(new File("instance.xml"));
} catch (SAXException e) {
    // instance document is invalid!
}

2
"Java 7. 사용." 실제로 Java 5에 포함되었습니다 .
앤드류 톰슨

4
이것은 기본적으로 허용되는 답변 과 동일 합니다 . 이 솔루션은 XML이 구문 분석 할 DOM을 불필요하게 빌드하기 때문에 약간 비효율적 인 것 같습니다 parser.parse(new File("instance.xml")). 는 validator을 받아 Source, 그래서 당신은 할 수 있습니다 validator.validate(new StreamSource(new File("instance.xml"))).
Alberto

이 방식으로 작업하면 SAXException이 xml 파일의 첫 번째 오류에서 발생하고 유효성 검사가 중지됩니다. 그러나 모든 (!) 오류를 알고 싶습니다. ErrorHandler (ErrorHandler를 구현하는 자체 클래스)를 대신 사용하면 모든 오류를 인식하지만 validator.validate의 try-catch-block에서 예외가 발생하지 않습니다. 유효성 검사를 호출하는 클래스의 오류를 어떻게 인식합니까? 내 유효성 검사기의 방법? 당신의 도움을 주셔서 감사합니다!
mrbela

"오류"(예 : 유효성 검사 오류) 및 "치명적 오류"(잘못 구성된 오류)가 있습니다. 치명적인 오류가 발생하면 일반적으로 구문 분석이 중지됩니다. 그러나 유효성 검사 오류는 멈추지 않습니다. 명시 적으로 예외를 던져야합니다. 따라서 ErrorHandler유효성 검사를 수행해야하는 경우 이를 제공 해야합니다.
Ludovic Kuty

1
인정 된 답변보다 코드가 더 깨끗하고 읽기 쉽습니다.
Clockwork

3

Linux-Machine을 사용하는 경우 무료 명령 줄 도구 SAXCount를 사용할 수 있습니다. 나는 이것이 매우 유용하다는 것을 알았다.

SAXCount -f -s -n my.xml

dtd 및 xsd에 대해 유효성을 검사합니다. 50MB 파일의 경우 5 초.

데비안 스퀴즈에서는 "libxerces-c-samples"패키지에 있습니다.

dtd와 xsd의 정의는 xml에 있어야합니다! 별도로 구성 할 수 없습니다.


2
이를 통해 vim (:! SAXCount -f -n -s %)의 간단한 XML 유효성 검사가 가능합니다.
Shane

4
또는 훌륭한 xmllint를 사용하십시오 xmllint --schema phone.xsd phone.xml(13ren의 답변에서)
rogerdpack

3

하나 더 답변 : 생성중인 파일의 유효성을 검사해야한다고 말했기 때문에 (쓰기) 먼저 쓰고 나서 유효성 검사를 위해 다시 읽는 대신 내용을 확인하는 것이 좋습니다. SAX 기반 라이터를 사용하는 경우 Xml 유효성 검사를위한 JDK API를 사용하여이 작업을 수행 할 수 있습니다. 그렇다면 'Validator.validate (source, result)'를 호출하여 유효성 검사기에서 링크하면됩니다. 출력이 필요한 곳.

또는 컨텐츠 (또는 stax를 사용하거나 사용할 수있는 라이브러리)를 작성하기 위해 Stax를 사용하는 경우 Woodstox 는 XMLStreamWriter를 사용할 때 유효성 검사를 직접 지원할 수도 있습니다. 수행 방법을 보여주는 블로그 항목 은 다음과 같습니다 .


StaxMan, 예쁜 인쇄 들여 쓰기를하는 XMLStreamWriter가 있습니까? 표준 구현이 아니라는 사실에 놀랐습니다. 또한 많이 사용되고 있습니까? 나는 그것이 올바른 길이라고 생각하지만 그것에 관심이 거의 없습니다.
13ren

단지 (하지만이 XMLStreamWriter에 아닙니다) StaxMate에 대해 여기에 귀하의 게시물을 발견 stackoverflow.com/questions/290326/stax-xml-formatting-in-java/...
13ren

예, StaxMate가 할 수 있습니다. 내부적으로 컨텐츠를 작성하기 위해 XMLStreamWriter를 사용하므로 유효성 검사기를 연결할 수도 있습니다.
StaxMan

2

프로그래밍 방식으로 XML 파일을 생성하는 경우 XMLBeans 라이브러리 를 살펴볼 수 있습니다. XMLBeans는 명령 행 도구를 사용하여 XSD를 기반으로 Java 오브젝트 세트를 자동으로 생성하고 패키지합니다. 그런 다음이 객체를 사용하여이 스키마를 기반으로 XML 문서를 작성할 수 있습니다.

스키마 유효성 검증을 기본적으로 지원하며 Java 오브젝트를 XML 문서로 변환하거나 그 반대로 변환 할 수 있습니다.

CastorJAXB 는 XMLBean과 유사한 용도로 사용되는 다른 Java 라이브러리입니다.


1

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
    }
}

0

도구 나 도서관을 찾고 있습니까?

라이브러리가 진행 되는 한 사실상의 표준은 C ++Java 버전 이 모두있는 Xerces2 입니다 .

그러나 무거운 솔루션입니다. 그러나 XSD 파일에 대해 XML의 유효성을 검사하는 것은 다소 무거운 문제입니다.

이를위한 도구는 XMLFox 가 알맞은 프리웨어 솔루션 인 것 같지만 개인적으로 사용하지 않은 것은 확실하지 않습니다.


0

온라인 스키마에 대한 유효성 검사

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);

로컬 스키마에 대해 유효성 검증

Java를 사용한 오프라인 XML 유효성 검사


0

Woodstox를 사용 하여 스키마에 대해 유효성을 검증하고 XML을 구문 분석하도록 StAX 구문 분석기를 구성하십시오.

예외가 발견되면 XML이 유효하지 않으면 유효하지 않습니다.

// create the XSD schema from your schema file
XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
XMLValidationSchema validationSchema = schemaFactory.createSchema(schemaInputStream);

// create the XML reader for your XML file
WstxInputFactory inputFactory = new WstxInputFactory();
XMLStreamReader2 xmlReader = (XMLStreamReader2) inputFactory.createXMLStreamReader(xmlInputStream);

try {
    // configure the reader to validate against the schema
    xmlReader.validateAgainst(validationSchema);

    // parse the XML
    while (xmlReader.hasNext()) {
        xmlReader.next();
    }

    // no exceptions, the XML is valid

} catch (XMLStreamException e) {

    // exceptions, the XML is not valid

} finally {
    xmlReader.close();
}

참고 : 여러 파일의 유효성을 검사해야하는 경우 XMLInputFactory및 파일을 재사용하여 XMLValidationSchema성능을 최대화해야합니다.


-3

한 번만 XSD에 대해 XML의 유효성을 검사해야했기 때문에 XMLFox를 사용해 보았습니다. 나는 그것이 매우 혼란스럽고 이상하다는 것을 알았습니다. 도움말 지침이 인터페이스와 일치하지 않는 것 같습니다.

사용하기 쉽고 훨씬 친숙한 LiquidXML Studio 2008 (v6)을 사용하게되었습니다 (UI는 자주 사용하는 Visual Basic 2008 Express와 매우 유사합니다). 단점 : 유효성 검사 기능이 무료 버전이 아니므로 30 일 평가판을 사용해야했습니다.


1
질문은 Java이지만이 대답은 아닙니다. :-(
james.garriss

공정하게 말하면, "java"라는 단어는 질문에 나타나지 않으며 태그 만 나타납니다. 답장이 아닌 그 질문을 듣습니다.
Mark Storer

제임스와 마크에게 감사드립니다.
Knom
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.