Merge branch '59-resolving-does-not-work-when-using-xslts-unparsed-text-function' into 'master'

Resolve "Resolving does not work when using XSLTs unparsed-text() function"

See merge request kosit/validator!29
This commit is contained in:
Andreas Penski 2020-07-29 12:13:18 +00:00
commit 592a1e87da
10 changed files with 58 additions and 16 deletions

View file

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- `getFailedAsserts()` and `isSchematronValid()` in [DefaultResult.java](https://github.com/itplr-kosit/validator/blob/master/src/main/java/de/kosit/validationtool/impl/DefaultResult.java) - `getFailedAsserts()` and `isSchematronValid()` in [DefaultResult.java](https://github.com/itplr-kosit/validator/blob/master/src/main/java/de/kosit/validationtool/impl/DefaultResult.java)
do not reflect actual schematron validation result do not reflect actual schematron validation result
- exception while resolving when using XSLT's `unparsed-text()` function within report generation
### Changed ### Changed
- engine info contains version number of the validator (configurations can output this in the report for maintainance puposes) - engine info contains version number of the validator (configurations can output this in the report for maintainance puposes)

View file

@ -7,6 +7,7 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; import javax.xml.validation.Validator;
import net.sf.saxon.lib.UnparsedTextURIResolver;
import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.Processor;
/** /**
@ -28,7 +29,7 @@ public interface ResolvingConfigurationStrategy {
/** /**
* Creates a preconfigured {@link SchemaFactory} for loading {@link javax.xml.validation.Schema} objects. The * Creates a preconfigured {@link SchemaFactory} for loading {@link javax.xml.validation.Schema} objects. The
* implementation is responsible for xml security. Take care * implementation is responsible for xml security. Take care
* *
* @return preconfigured {@link SchemaFactory} * @return preconfigured {@link SchemaFactory}
*/ */
SchemaFactory createSchemaFactory(); SchemaFactory createSchemaFactory();
@ -37,9 +38,9 @@ public interface ResolvingConfigurationStrategy {
* Returns a preconfigured {@link Processor Saxon Processor} for various tasks within the Validator. The validator * Returns a preconfigured {@link Processor Saxon Processor} for various tasks within the Validator. The validator
* leverages the saxon s9api for internal processing e.g. xml reading and writing. So this is the main object to secure * leverages the saxon s9api for internal processing e.g. xml reading and writing. So this is the main object to secure
* for reading, transforming and writing xml files. * for reading, transforming and writing xml files.
* *
* Note: you need exactly one instance for all validator related processing. * Note: you need exactly one instance for all validator related processing.
* *
* @return a preconfigured {@link Processor} * @return a preconfigured {@link Processor}
*/ */
Processor getProcessor(); Processor getProcessor();
@ -52,12 +53,20 @@ public interface ResolvingConfigurationStrategy {
* This URIResolver is used to dereference the URIs appearing in <code>xsl:import</code>, <code>xsl:include</code>, and * This URIResolver is used to dereference the URIs appearing in <code>xsl:import</code>, <code>xsl:include</code>, and
* <code>xsl:import-schema</code> declarations. * <code>xsl:import-schema</code> declarations.
* </p> * </p>
* *
* @param scenarioRepository an optional repository, your implementation might not need this * @param scenarioRepository an optional repository, your implementation might not need this
* @return a preconfigured {@link URIResolver} * @return a preconfigured {@link URIResolver}
*/ */
URIResolver createResolver(URI scenarioRepository); URIResolver createResolver(URI scenarioRepository);
/**
* Creates a specific implementation for resolving objects referenced via XSLT's <code>unparsed-text()</code> function.
*
* @param scenarioRepository an optional repository, your implementation might not need this
* @return a preconfigured {@link net.sf.saxon.lib.UnparsedTextURIResolver} or null for using saxons default
*/
UnparsedTextURIResolver createUnparsedTextURIResolver(URI scenarioRepository);
/** /**
* Creates a preconfigured {@link Validator } instance for a given schema for xml file validation. The implementation * Creates a preconfigured {@link Validator } instance for a given schema for xml file validation. The implementation
* takes care about security and reference resolving strategies. * takes care about security and reference resolving strategies.

View file

@ -52,6 +52,7 @@ import de.kosit.validationtool.model.scenarios.ResourceType;
import de.kosit.validationtool.model.scenarios.ScenarioType; import de.kosit.validationtool.model.scenarios.ScenarioType;
import de.kosit.validationtool.model.scenarios.ValidateWithSchematron; import de.kosit.validationtool.model.scenarios.ValidateWithSchematron;
import net.sf.saxon.lib.UnparsedTextURIResolver;
import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XPathCompiler; import net.sf.saxon.s9api.XPathCompiler;
@ -77,6 +78,8 @@ public class ContentRepository {
private final URIResolver resolver; private final URIResolver resolver;
private final UnparsedTextURIResolver unparsedTextURIResolver;
private final SchemaFactory schemaFactory; private final SchemaFactory schemaFactory;
@Getter @Getter
@ -94,6 +97,7 @@ public class ContentRepository {
this.resolvingConfigurationStrategy = strategy; this.resolvingConfigurationStrategy = strategy;
this.processor = this.resolvingConfigurationStrategy.getProcessor(); this.processor = this.resolvingConfigurationStrategy.getProcessor();
this.resolver = this.resolvingConfigurationStrategy.createResolver(repository); this.resolver = this.resolvingConfigurationStrategy.createResolver(repository);
this.unparsedTextURIResolver = this.resolvingConfigurationStrategy.createUnparsedTextURIResolver(repository);
this.schemaFactory = this.resolvingConfigurationStrategy.createSchemaFactory(); this.schemaFactory = this.resolvingConfigurationStrategy.createSchemaFactory();
} }
@ -251,14 +255,18 @@ public class ContentRepository {
} }
/** /**
* Erzeugt einen resolver für dieses Repository, der nur relativ auflösen kann * Returns the {@link URIResolver} to use for resolving xml artifacts.
* *
* @return ein neuer Resolver * @return the resolver
*/ */
public URIResolver getResolver() { public URIResolver getResolver() {
return this.resolver; return this.resolver;
} }
public UnparsedTextURIResolver getUnparsedTextURIResolver() {
return this.unparsedTextURIResolver;
}
/** /**
* Gibt eine Transformation zurück. * Gibt eine Transformation zurück.
* *

View file

@ -85,7 +85,8 @@ public class DefaultCheck implements Check {
this.checkSteps.add(new SchemaValidationAction(content.getResolvingConfigurationStrategy(), processor)); this.checkSteps.add(new SchemaValidationAction(content.getResolvingConfigurationStrategy(), processor));
this.checkSteps.add(new SchematronValidationAction(content.getResolver(), this.conversionService)); this.checkSteps.add(new SchematronValidationAction(content.getResolver(), this.conversionService));
this.checkSteps.add(new ValidateReportInputAction(this.conversionService, content.getReportInputSchema())); this.checkSteps.add(new ValidateReportInputAction(this.conversionService, content.getReportInputSchema()));
this.checkSteps.add(new CreateReportAction(processor, this.conversionService, content.getResolver())); this.checkSteps.add(
new CreateReportAction(processor, this.conversionService, content.getResolver(), content.getUnparsedTextURIResolver()));
this.checkSteps.add(new ComputeAcceptanceAction()); this.checkSteps.add(new ComputeAcceptanceAction());
} }

View file

@ -28,7 +28,6 @@ import javax.xml.bind.Marshaller;
import javax.xml.bind.util.JAXBSource; import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.URIResolver; import javax.xml.transform.URIResolver;
import lombok.extern.slf4j.Slf4j;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler; import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver; import org.xml.sax.EntityResolver;
@ -41,6 +40,7 @@ import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.AttributesImpl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import de.kosit.validationtool.impl.CollectingErrorEventHandler; import de.kosit.validationtool.impl.CollectingErrorEventHandler;
import de.kosit.validationtool.impl.ConversionService; import de.kosit.validationtool.impl.ConversionService;
@ -48,6 +48,7 @@ import de.kosit.validationtool.impl.EngineInformation;
import de.kosit.validationtool.impl.Scenario; import de.kosit.validationtool.impl.Scenario;
import de.kosit.validationtool.model.reportInput.XMLSyntaxError; import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
import net.sf.saxon.lib.UnparsedTextURIResolver;
import net.sf.saxon.s9api.BuildingContentHandler; import net.sf.saxon.s9api.BuildingContentHandler;
import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.Processor;
@ -175,6 +176,8 @@ public class CreateReportAction implements CheckAction {
private final URIResolver resolver; private final URIResolver resolver;
private final UnparsedTextURIResolver unparsedTextURIResolver;
private static XsltExecutable loadFromScenario(final Scenario object) { private static XsltExecutable loadFromScenario(final Scenario object) {
return object.getReportTransformation().getExecutable(); return object.getReportTransformation().getExecutable();
} }
@ -198,7 +201,9 @@ public class CreateReportAction implements CheckAction {
final CollectingErrorEventHandler e = new CollectingErrorEventHandler(); final CollectingErrorEventHandler e = new CollectingErrorEventHandler();
transformer.setMessageListener(e); transformer.setMessageListener(e);
transformer.setURIResolver(this.resolver); transformer.setURIResolver(this.resolver);
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver); if (this.unparsedTextURIResolver != null) {
transformer.getUnderlyingController().setUnparsedTextURIResolver(this.unparsedTextURIResolver);
}
if (parsedDocument != null) { if (parsedDocument != null) {
transformer.setParameter(new QName("input-document"), parsedDocument); transformer.setParameter(new QName("input-document"), parsedDocument);
} }

View file

@ -20,7 +20,6 @@
package de.kosit.validationtool.impl.xml; package de.kosit.validationtool.impl.xml;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.net.URI; import java.net.URI;
@ -32,6 +31,8 @@ import javax.xml.transform.stream.StreamSource;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.sf.saxon.Configuration; import net.sf.saxon.Configuration;
import net.sf.saxon.lib.StandardUnparsedTextResolver;
import net.sf.saxon.lib.UnparsedTextURIResolver;
import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.XPathException;
/** /**
@ -41,7 +42,7 @@ import net.sf.saxon.trans.XPathException;
* @author Andreas Penski * @author Andreas Penski
*/ */
@RequiredArgsConstructor() @RequiredArgsConstructor()
public class RelativeUriResolver implements URIResolver { public class RelativeUriResolver implements URIResolver, UnparsedTextURIResolver {
/** the base uri */ /** the base uri */
private final URI baseUri; private final URI baseUri;
@ -93,6 +94,16 @@ public class RelativeUriResolver implements URIResolver {
return r.startsWith(base); return r.startsWith(base);
} }
// from UnparsedTextURIResolver
@Override
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
if (isUnderBaseUri(absoluteURI, this.baseUri)) {
return new StandardUnparsedTextResolver().resolve(absoluteURI, encoding, config);
} else {
throw new XPathException(String.format("The resolved transformation artifact %s is not within the configured repository %s",
absoluteURI, this.baseUri));
}
}
} }

View file

@ -109,6 +109,11 @@ public class StrictRelativeResolvingStrategy extends BaseResolvingStrategy {
return new RelativeUriResolver(repositoryURI); return new RelativeUriResolver(repositoryURI);
} }
@Override
public UnparsedTextURIResolver createUnparsedTextURIResolver(final URI scenarioRepository) {
return new RelativeUriResolver(scenarioRepository);
}
@Override @Override
public Validator createValidator(final Schema schema) { public Validator createValidator(final Schema schema) {
if (schema == null) { if (schema == null) {

View file

@ -9,11 +9,8 @@ import static org.mockito.Mockito.when;
import javax.xml.transform.Source; import javax.xml.transform.Source;
import org.hamcrest.Matchers;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import de.kosit.validationtool.api.InputFactory; import de.kosit.validationtool.api.InputFactory;
import de.kosit.validationtool.impl.ContentRepository; import de.kosit.validationtool.impl.ContentRepository;
@ -42,7 +39,8 @@ public class CreateReportActionTest {
@Before @Before
public void setup() { public void setup() {
this.repository = Simple.createContentRepository(); this.repository = Simple.createContentRepository();
this.action = new CreateReportAction(this.repository.getProcessor(), new ConversionService(), this.repository.getResolver()); this.action = new CreateReportAction(this.repository.getProcessor(), new ConversionService(), this.repository.getResolver(),
this.repository.getUnparsedTextURIResolver());
} }
@Test @Test
@ -72,7 +70,7 @@ public class CreateReportActionTest {
public void testExecutionException() throws SaxonApiException { public void testExecutionException() throws SaxonApiException {
final Processor p = mock(Processor.class); final Processor p = mock(Processor.class);
final DocumentBuilder documentBuilder = mock(DocumentBuilder.class); final DocumentBuilder documentBuilder = mock(DocumentBuilder.class);
this.action = new CreateReportAction(p, new ConversionService(), null); this.action = new CreateReportAction(p, new ConversionService(), null, null);
when(p.newDocumentBuilder()).thenReturn(documentBuilder); when(p.newDocumentBuilder()).thenReturn(documentBuilder);
when(documentBuilder.build(any(Source.class))).thenThrow(new SaxonApiException("mocked")); when(documentBuilder.build(any(Source.class))).thenThrow(new SaxonApiException("mocked"));

View file

@ -37,6 +37,9 @@
<result> <result>
<xsl:copy-of select="." /> <xsl:copy-of select="." />
</result> </result>
<text>
<xsl:value-of select="unparsed-text('some.txt','UTF-8')" />
</text>
</report> </report>
</xsl:template> </xsl:template>

View file

@ -0,0 +1 @@
This content should be transferred to the result document