diff --git a/xml-2/pom.xml b/xml-2/pom.xml
index 025ad682ad..c4882b0a53 100644
--- a/xml-2/pom.xml
+++ b/xml-2/pom.xml
@@ -20,6 +20,12 @@
dom4j
${dom4j.version}
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit-jupiter.version}
+ test
+
diff --git a/xml-2/src/main/java/com/baeldung/xml/validation/XmlErrorHandler.java b/xml-2/src/main/java/com/baeldung/xml/validation/XmlErrorHandler.java
new file mode 100644
index 0000000000..2a4651a029
--- /dev/null
+++ b/xml-2/src/main/java/com/baeldung/xml/validation/XmlErrorHandler.java
@@ -0,0 +1,35 @@
+package com.baeldung.xml.validation;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlErrorHandler implements ErrorHandler {
+
+ private List exceptions;
+
+ public XmlErrorHandler() {
+ this.exceptions = new ArrayList<>();
+ }
+
+ public List getExceptions() {
+ return exceptions;
+ }
+
+ @Override
+ public void warning(SAXParseException exception) {
+ exceptions.add(exception);
+ }
+
+ @Override
+ public void error(SAXParseException exception) {
+ exceptions.add(exception);
+ }
+
+ @Override
+ public void fatalError(SAXParseException exception) {
+ exceptions.add(exception);
+ }
+}
diff --git a/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java b/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java
new file mode 100644
index 0000000000..7d8f531bfa
--- /dev/null
+++ b/xml-2/src/main/java/com/baeldung/xml/validation/XmlValidator.java
@@ -0,0 +1,62 @@
+package com.baeldung.xml.validation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class XmlValidator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(XmlValidator.class);
+
+ private String xsdPath;
+ private String xmlPath;
+
+ public XmlValidator(String xsdPath, String xmlPath) {
+ this.xsdPath = xsdPath;
+ this.xmlPath = xmlPath;
+ }
+
+ public boolean isValid() throws IOException, SAXException {
+ Validator validator = initValidator(xsdPath);
+ try {
+ validator.validate(new StreamSource(getFile(xmlPath)));
+ return true;
+ } catch (SAXException e) {
+ return false;
+ }
+ }
+
+ public List listParsingExceptions() throws IOException, SAXException {
+ XmlErrorHandler xsdErrorHandler = new XmlErrorHandler();
+ Validator validator = initValidator(xsdPath);
+ validator.setErrorHandler(xsdErrorHandler);
+ try {
+ validator.validate(new StreamSource(getFile(xmlPath)));
+ } catch (SAXParseException e) {}
+ xsdErrorHandler.getExceptions().forEach(e -> LOGGER.info(e.getMessage()));
+ return xsdErrorHandler.getExceptions();
+ }
+
+ private Validator initValidator(String xsdPath) throws SAXException {
+ SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Source schemaFile = new StreamSource(getFile(xsdPath));
+ Schema schema = factory.newSchema(schemaFile);
+ return schema.newValidator();
+ }
+
+ private File getFile(String location) {
+ return new File(getClass().getClassLoader().getResource(location).getFile());
+ }
+
+}
diff --git a/xml-2/src/main/resources/xml/validation/baeldung.xml b/xml-2/src/main/resources/xml/validation/baeldung.xml
new file mode 100644
index 0000000000..31ae4b4aa6
--- /dev/null
+++ b/xml-2/src/main/resources/xml/validation/baeldung.xml
@@ -0,0 +1,8 @@
+
+
+ Baeldung
+
+ 00001
+ New York
+
+
\ No newline at end of file
diff --git a/xml-2/src/main/resources/xml/validation/full-person.xsd b/xml-2/src/main/resources/xml/validation/full-person.xsd
new file mode 100644
index 0000000000..ea268c3a47
--- /dev/null
+++ b/xml-2/src/main/resources/xml/validation/full-person.xsd
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xml-2/src/main/resources/xml/validation/person.xsd b/xml-2/src/main/resources/xml/validation/person.xsd
new file mode 100644
index 0000000000..22c41b6a22
--- /dev/null
+++ b/xml-2/src/main/resources/xml/validation/person.xsd
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xml-2/src/test/java/com/baeldung/xml/validation/XmlValidatorUnitTest.java b/xml-2/src/test/java/com/baeldung/xml/validation/XmlValidatorUnitTest.java
new file mode 100644
index 0000000000..2eb20a9bf2
--- /dev/null
+++ b/xml-2/src/test/java/com/baeldung/xml/validation/XmlValidatorUnitTest.java
@@ -0,0 +1,35 @@
+package com.baeldung.xml.validation;
+
+import org.junit.jupiter.api.Test;
+import org.xml.sax.SAXException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class XmlValidatorUnitTest {
+
+ private static final String BAELDUNG_XML_PATH = "xml/validation/baeldung.xml";
+ private static final String PERSON_XSD_PATH = "xml/validation/person.xsd";
+ private static final String FULL_PERSON_XSD_PATH = "xml/validation/full-person.xsd";
+
+ @Test
+ public void givenValidXML_WhenIsValid_ThenTrue() throws IOException, SAXException {
+ assertTrue(new XmlValidator(PERSON_XSD_PATH, BAELDUNG_XML_PATH).isValid());
+ }
+
+ @Test
+ public void givenInvalidXML_WhenIsValid_ThenFalse() throws IOException, SAXException {
+ assertFalse(new XmlValidator(FULL_PERSON_XSD_PATH, BAELDUNG_XML_PATH).isValid());
+ }
+
+ @Test
+ public void givenValidXML_WhenListParsingExceptions_ThenNone() throws IOException, SAXException {
+ assertEquals(0, new XmlValidator(PERSON_XSD_PATH, BAELDUNG_XML_PATH).listParsingExceptions().size());
+ }
+
+ @Test
+ public void givenInvalidXML_WhenListParsingExceptions_ThenHasThree() throws IOException, SAXException {
+ assertEquals(3, new XmlValidator(FULL_PERSON_XSD_PATH, BAELDUNG_XML_PATH).listParsingExceptions().size());
+ }
+
+}