com.crabshue.commons.xml.schema.SchemaLocationSaxHandler Maven / Gradle / Ivy
package com.crabshue.commons.xml.schema;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.crabshue.commons.exceptions.SystemException;
import com.crabshue.commons.xml.exceptions.XmlErrorContext;
import com.crabshue.commons.xml.exceptions.XmlErrorType;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
/**
* {@link DefaultHandler SAX handler} to parse the schema URL defined in an XML file.
*
* The schema URL is searched in the attribute {@code xsi:schemaLocation} or {@code xsi:noNamespaceSchemaLocation}.
*
*
*/
@Slf4j
final class SchemaLocationSaxHandler extends DefaultHandler {
private static final String XSI_SCHEMA_LOCATION = "xsi:schemaLocation";
private static final String XSI_NO_NAMESPACE_SCHEMA_LOCATION = "xsi:noNamespaceSchemaLocation";
private final File schemaFolder;
private URL schemaUrl;
public SchemaLocationSaxHandler(@NonNull final File schemaFolder) {
this.schemaFolder = schemaFolder;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
if (schemaUrl == null) {
Optional schemaPath = getSchemaLocationAttribute(attributes);
if (!schemaPath.isPresent()) {
schemaPath = getNoNamespaceSchemaLocation(attributes);
}
if (schemaPath.isPresent()) {
schemaUrl = buildSchemaUrl(schemaPath.get());
}
}
}
private Optional getSchemaLocationAttribute(final Attributes attributes) {
Validate.notNull(attributes);
Optional ret = Optional.empty();
final String attributeValue = attributes.getValue(XSI_SCHEMA_LOCATION);
if (StringUtils.isNotBlank(attributeValue)) {
logger.debug("xsi:schemaLocation is [{}]", attributeValue);
final String pathToSchema = StringUtils.substringAfter(attributeValue, " ");
ret = Optional.ofNullable(StringUtils.trim(pathToSchema));
}
return ret;
}
private Optional getNoNamespaceSchemaLocation(final Attributes attributes) {
Validate.notNull(attributes);
final String candidate = attributes.getValue(XSI_NO_NAMESPACE_SCHEMA_LOCATION);
final Optional ret = Optional.ofNullable(candidate);
logger.debug("xsi:noNamespaceSchemaLocation is [{}]", ret);
return ret;
}
private URL buildSchemaUrl(final String schemaPath) {
Validate.notNull(schemaPath);
final URL ret;
try {
final boolean protocolIsOkForUrl = StringUtils.startsWith(schemaPath, Protocol.HTTP.getPrefix())
|| StringUtils.startsWith(schemaPath, Protocol.HTTPS.getPrefix())
|| StringUtils.startsWith(schemaPath, Protocol.FILE.getPrefix());
// protocol is http: https: or file:
if (protocolIsOkForUrl) {
ret = new URL(schemaPath);
}
// if schema path has no protocol
else {
final File schemaPathAsFile = new File(schemaPath);
//if path is absolute
if (schemaPathAsFile.isAbsolute()) {
ret = new URL(schemaPath);
}
// if path is relative
else {
final File schemaFile = new File(schemaFolder, schemaPath);
ret = schemaFile.toURI().toURL();
}
}
} catch (MalformedURLException e) {
throw new SystemException(XmlErrorType.MALFORMED_URI, e)
.addContextValue(XmlErrorContext.URL, schemaPath);
}
return ret;
}
public URL getSchemaUrl() {
return schemaUrl;
}
}