|
3 | 3 | // SPDX-License-Identifier: Apache-2.0
|
4 | 4 | package org.lfenergy.compas.scl.validator.xsd;
|
5 | 5 |
|
| 6 | +import org.apache.xerces.impl.Constants; |
| 7 | +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; |
6 | 8 | import org.lfenergy.compas.scl.validator.model.ValidationError;
|
7 | 9 | import org.slf4j.Logger;
|
8 | 10 | import org.slf4j.LoggerFactory;
|
| 11 | +import org.w3c.dom.Node; |
9 | 12 | import org.xml.sax.ErrorHandler;
|
| 13 | +import org.xml.sax.SAXException; |
10 | 14 | import org.xml.sax.SAXParseException;
|
11 | 15 |
|
| 16 | +import javax.xml.validation.Validator; |
12 | 17 | import java.util.List;
|
13 | 18 |
|
| 19 | +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.CREATE_XPATH_ELEMENT_ERROR_CODE; |
| 20 | + |
14 | 21 | public class XSDErrorHandler implements ErrorHandler {
|
15 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(XSDErrorHandler.class);
|
16 | 23 |
|
17 | 24 | public static final String DEFAULT_PREFIX = "XSD/";
|
18 | 25 | public static final String DEFAULT_RULE_NAME = DEFAULT_PREFIX + "general";
|
19 | 26 |
|
20 |
| - private List<ValidationError> errorList; |
| 27 | + private final Validator validator; |
| 28 | + private final List<ValidationError> errorList; |
21 | 29 |
|
22 |
| - public XSDErrorHandler(List<ValidationError> errorList) { |
| 30 | + public XSDErrorHandler(Validator validator, List<ValidationError> errorList) { |
| 31 | + this.validator = validator; |
23 | 32 | this.errorList = errorList;
|
24 | 33 | }
|
25 | 34 |
|
26 | 35 | @Override
|
27 |
| - public void warning(SAXParseException exception) { |
| 36 | + public void warning(SAXParseException exception) throws SAXException { |
28 | 37 | var validationError = createValidationError(exception);
|
29 | 38 | errorList.add(validationError);
|
30 | 39 |
|
31 |
| - LOGGER.debug("XSD Validation - warning: '{}' (Line number {}, Column number {})", |
| 40 | + LOGGER.debug("XSD Validation - warning: '{}' (XPath {})", |
32 | 41 | validationError.getMessage(),
|
33 |
| - validationError.getLineNumber(), |
34 |
| - validationError.getColumnNumber()); |
| 42 | + validationError.getXpath()); |
35 | 43 | }
|
36 | 44 |
|
37 | 45 | @Override
|
38 |
| - public void error(SAXParseException exception) { |
| 46 | + public void error(SAXParseException exception) throws SAXException { |
39 | 47 | var validationError = createValidationError(exception);
|
40 | 48 | errorList.add(validationError);
|
41 | 49 |
|
42 |
| - LOGGER.debug("XSD Validation - error: '{}' (Line number {}, Column number {})", |
| 50 | + LOGGER.debug("XSD Validation - error: '{}' (XPath {})", |
43 | 51 | validationError.getMessage(),
|
44 |
| - validationError.getLineNumber(), |
45 |
| - validationError.getColumnNumber()); |
| 52 | + validationError.getXpath()); |
46 | 53 | }
|
47 | 54 |
|
48 | 55 | @Override
|
49 |
| - public void fatalError(SAXParseException exception) { |
| 56 | + public void fatalError(SAXParseException exception) throws SAXException { |
50 | 57 | var validationError = createValidationError(exception);
|
51 | 58 | errorList.add(validationError);
|
52 | 59 |
|
53 |
| - LOGGER.debug("XSD Validation - fatal error, stopping: '{}' (Line number {}, Column number {})", |
| 60 | + LOGGER.debug("XSD Validation - fatal error, stopping: '{}' (XPath {})", |
54 | 61 | validationError.getMessage(),
|
55 |
| - validationError.getLineNumber(), |
56 |
| - validationError.getColumnNumber()); |
| 62 | + validationError.getXpath()); |
57 | 63 | }
|
58 | 64 |
|
59 |
| - private ValidationError createValidationError(SAXParseException exception) { |
| 65 | + private ValidationError createValidationError(SAXParseException exception) throws SAXException { |
60 | 66 | var validationError = new ValidationError();
|
61 | 67 | var xsdMessage = exception.getMessage();
|
62 | 68 | validationError.setMessage(getMessage(xsdMessage));
|
63 | 69 | validationError.setRuleName(getRuleName(xsdMessage));
|
64 |
| - validationError.setLineNumber(exception.getLineNumber()); |
65 |
| - validationError.setColumnNumber(exception.getColumnNumber()); |
| 70 | + validationError.setXpath(getXPath(getCurrentNode())); |
66 | 71 | return validationError;
|
67 | 72 | }
|
68 | 73 |
|
@@ -93,4 +98,36 @@ String getMessage(String xsdMessage) {
|
93 | 98 | }
|
94 | 99 | return message;
|
95 | 100 | }
|
| 101 | + |
| 102 | + String getXPath(Node node) { |
| 103 | + if (node != null) { |
| 104 | + var parent = node.getParentNode(); |
| 105 | + if (parent != null && parent != node.getOwnerDocument()) { |
| 106 | + return getXPath(parent) + "/" + node.getNodeName() + "[" + getIndex(parent, node) + "]"; |
| 107 | + } |
| 108 | + return "/" + node.getNodeName(); |
| 109 | + } |
| 110 | + return null; |
| 111 | + } |
| 112 | + |
| 113 | + int getIndex(Node parent, Node child) { |
| 114 | + var children = parent.getChildNodes(); |
| 115 | + var index = 0; |
| 116 | + for (int i = 0; i < children.getLength(); i++) { |
| 117 | + var listItem = children.item(i); |
| 118 | + if (listItem.getNodeName().equals(child.getNodeName())) { |
| 119 | + index++; |
| 120 | + if (listItem == child) { |
| 121 | + return index; |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + throw new SclValidatorException(CREATE_XPATH_ELEMENT_ERROR_CODE, "Error determining index of child element"); |
| 126 | + } |
| 127 | + |
| 128 | + private Node getCurrentNode() throws SAXException { |
| 129 | + // Get prop "http://apache.org/xml/properties/dom/current-element-node" |
| 130 | + // See https://xerces.apache.org/xerces2-j/properties.html#dom.current-element-node |
| 131 | + return (Node) validator.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY); |
| 132 | + } |
96 | 133 | }
|
0 commit comments