Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions cli/src/main/java-templates/AbstractNormalize.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import java.util.concurrent.Callable;

import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltPackage;
import net.sf.saxon.s9api.SaxonApiException;

import de.wwu.scdh.annotation.selection.resource.DOMResource;
import de.wwu.scdh.annotation.selection.resource.ResourceBuilder;
Expand All @@ -26,7 +30,22 @@ abstract class AbstractNormalize {

protected static final Processor PROC = new Processor();

enum Normalizer {
XPathCompiler compiler = PROC.newXPathCompiler();

protected void compileXPathLibrary() {
try {
File library = new File(DOMResource.class.getResource("/xslt/xpath.xsl").getPath());
XsltCompiler xsltCompiler = PROC.newXsltCompiler();
XsltPackage functionLibrary = xsltCompiler.compilePackage(library);
compiler.addXsltFunctionLibrary(functionLibrary);
compiler.declareNamespace("sel", "http://wwu.de/scdh/selection-engine/xpaths");
} catch (SaxonApiException e) {
System.err.println("failed to load xpath library: " + e.getMessage());
System.exit(2);
}
}

enum Normalizer {
FROM_ROOT_CLARK,
FROM_DEEPEST_ID_CLARK
}
Expand Down Expand Up @@ -148,12 +167,10 @@ protected String getNormalizerXPath() throws CliException {
}

protected XPathNormalizerWithXPath getXPathNormalizer() throws CliException {
return new XPathNormalizerWithXPath(getNormalizerXPath());
return new XPathNormalizerWithXPath(PROC.newXPathCompiler(), getNormalizerXPath());
}

protected NormalizerFactory getNormalizerFactory() {
return new NormalizerFactory();
}
protected NormalizerFactory getNormalizerFactory(){ return new NormalizerFactory(PROC.newXPathCompiler()); }

protected RewriterConfig getRewriterConfig() throws CliException {
return new RewriterConfig(mode, false, getNormalizerXPath(), true, true);
Expand Down
4 changes: 2 additions & 2 deletions cli/src/main/java-templates/Normalize.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ public Integer call() throws Exception {
XPathNormalizerWithXPath xpathNormalizer;
if (normalizer.equals(Normalizer.FROM_DEEPEST_ID_CLARK)) {
try {
xpathNormalizer = new XPathNormalizerWithXPath(XPathNormalizerWithXPath.FROM_DEEPEST_ID_CLARK_XPATH);
xpathNormalizer = new XPathNormalizerWithXPath(compiler, XPathNormalizerWithXPath.FROM_DEEPEST_ID_CLARK_XPATH);
} catch (Exception e) {
System.err.println(e.getMessage());
return 2;
}
} else if (normalizer.equals(Normalizer.FROM_ROOT_CLARK)) {
try {
xpathNormalizer = new XPathNormalizerWithXPath(XPathNormalizerWithXPath.FROM_ROOT_CLARK_XPATH);
xpathNormalizer = new XPathNormalizerWithXPath(compiler, XPathNormalizerWithXPath.FROM_ROOT_CLARK_XPATH);
} catch (Exception e) {
System.err.println(e.getMessage());
return 2;
Expand Down
4 changes: 2 additions & 2 deletions cli/src/main/java-templates/TransformSimple.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ public Integer call() throws Exception {
RewriterFactory factory;
Rewriter rewriter;
if (backward) {
factory = new BackwardMappingFactory();
factory = new BackwardMappingFactory(compiler);
rewriter = factory.getRewriter
(preimage.getImage().getPointClass(),
XPathRefinedByRFC5147CharScheme.class,
getRewriterConfig());
} else {
factory = new ForwardMappingFactory();
factory = new ForwardMappingFactory(compiler);
rewriter = factory.getRewriter
(XPathRefinedByRFC5147CharScheme.class,
preimage.getImage().getPointClass(),
Expand Down
30 changes: 30 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,36 @@
</executions>
</plugin>

<plugin>
<groupId>com.nkutsche</groupId>
<artifactId>xspec-maven-plugin</artifactId>
<version>2.1.1</version>
<dependencies>
<dependency>
<groupId>io.xspec</groupId>
<artifactId>xspec</artifactId>
<version>2.2.4</version>
<classifier>enduser-files</classifier>
<type>zip</type>
</dependency>
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>${saxon.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>run-xspec</goal>
</goals>
<configuration>
<testDir>${project.basedir}/src/main/resources/xslt</testDir>
</configuration>
</execution>
</executions>
</plugin>

</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@
import de.wwu.scdh.annotation.selection.RewriterFactory;
import de.wwu.scdh.annotation.selection.point.RFC5147CharScheme;
import de.wwu.scdh.annotation.selection.point.XPathRefinedByRFC5147CharScheme;
import net.sf.saxon.s9api.XPathCompiler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BackwardMappingFactory implements RewriterFactory {

private static Logger Log = LoggerFactory.getLogger(ForwardMappingFactory.class);

private final XPathCompiler compiler;

/**
* Creates a new {@link BackwardMappingFactory} with a {@link XPathCompiler}.
* @param compiler - A compiler used for evaluating XPath expressions.
*/
public BackwardMappingFactory(XPathCompiler compiler) {
this.compiler = compiler;
}

// @SuppressWarnings("unchecked")
@Override
public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Rewriter<R, P1, P2>> RW getRewriter(
Expand All @@ -24,10 +35,10 @@ public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Re
RW rc;
if (XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point1)
&& XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point2)) {
rc = (RW) new XPathRefinedByRFC5147CharSchemeBackwardMapper(config.getXPath());
rc = (RW) new XPathRefinedByRFC5147CharSchemeBackwardMapper(compiler, config.getXPath());
} else if (RFC5147CharScheme.class.isAssignableFrom(point1)
&& XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point2)) {
rc = (RW) new XPathRefinedByRFC5147CharSchemeToTextBackwardMapper(config.getXPath());
rc = (RW) new XPathRefinedByRFC5147CharSchemeToTextBackwardMapper(compiler, config.getXPath());
} else {
Log.error("no backward mapping for {}, {}", point1.getCanonicalName(), point2.getCanonicalName());
throw new ConfigurationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@
import de.wwu.scdh.annotation.selection.RewriterFactory;
import de.wwu.scdh.annotation.selection.point.RFC5147CharScheme;
import de.wwu.scdh.annotation.selection.point.XPathRefinedByRFC5147CharScheme;
import net.sf.saxon.s9api.XPathCompiler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ForwardMappingFactory implements RewriterFactory {

private static Logger Log = LoggerFactory.getLogger(ForwardMappingFactory.class);

private final XPathCompiler compiler;

/**
* Creates a new {@link BackwardMappingFactory} with a {@link XPathCompiler}.
* @param compiler - A compiler used for evaluating XPath expressions.
*/
public ForwardMappingFactory(XPathCompiler compiler) {
this.compiler = compiler;
}

// @SuppressWarnings("unchecked")
@Override
public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Rewriter<R, P1, P2>> RW getRewriter(
Expand All @@ -26,10 +37,10 @@ public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Re
RW rc;
if (XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point1)
&& XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point2)) {
rc = (RW) new XPathRefinedByRFC5147CharSchemeForwardMapper(config.getXPath());
rc = (RW) new XPathRefinedByRFC5147CharSchemeForwardMapper(compiler, config.getXPath());
} else if (XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point1)
&& RFC5147CharScheme.class.isAssignableFrom(point2)) {
rc = (RW) new XPathRefinedByRFC5147CharSchemeToTextForwardMapper(config.getXPath());
rc = (RW) new XPathRefinedByRFC5147CharSchemeToTextForwardMapper(compiler, config.getXPath());
} else {
Log.error("no forward mapping for {}, {}", point1.getCanonicalName(), point2.getCanonicalName());
throw new ConfigurationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,20 @@
import de.wwu.scdh.annotation.selection.RewriterConfig;
import de.wwu.scdh.annotation.selection.RewriterFactory;
import de.wwu.scdh.annotation.selection.point.XPathRefinedByRFC5147CharScheme;
import net.sf.saxon.s9api.XPathCompiler;

public class NormalizerFactory implements RewriterFactory {

private final XPathCompiler compiler;

/**
* Creates a new {@link BackwardMappingFactory} with a {@link XPathCompiler}.
* @param compiler - A compiler used for evaluating XPath expressions.
*/
public NormalizerFactory(XPathCompiler compiler) {
this.compiler = compiler;
}

// @SuppressWarnings("unchecked")
@Override
public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Rewriter<R, P1, P2>> RW getRewriter(
Expand All @@ -19,7 +30,7 @@ public <R extends Resource<?>, P1 extends Point, P2 extends Point, RW extends Re
RW rc;
if (XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point2)
&& XPathRefinedByRFC5147CharScheme.class.isAssignableFrom(point2)) {
rc = (RW) new XPathNormalizerWithXPath(config.getXPath());
rc = (RW) new XPathNormalizerWithXPath(compiler, config.getXPath());
} else {
throw new ConfigurationException(
"no rewriter for " + point1.getClass().getCanonicalName() + " ; "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import de.wwu.scdh.annotation.selection.*;
import de.wwu.scdh.annotation.selection.point.XPathRefinedByRFC5147CharScheme;
import de.wwu.scdh.annotation.selection.resource.DOMResource;
import de.wwu.scdh.annotation.selection.resource.S9ApiResource;
import java.util.List;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XdmNode;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The same position (or range) in a {@link DOMResource} can be
Expand All @@ -19,7 +19,7 @@
*
* Normalization of selectors is a 2-stage process: 1) In the first
* stage, the text position (or range) which is referenced by the
* selector, has to be found. A pair containing a text node and a RFC
* selector, has to be found. A pair containing a text node and an RFC
* 5147 character scheme position is returned. 2) In the second stage,
* this position is expressed as a selector again, i.e., the node is
* referenced with an XPath, where the XPath may be written as a path
Expand All @@ -46,14 +46,12 @@
public abstract class XPathNormalizer extends XPathRewriterBase
implements Rewriter<DOMResource, XPathRefinedByRFC5147CharScheme, XPathRefinedByRFC5147CharScheme> {

private static final Logger LOG = LoggerFactory.getLogger(XPathNormalizer.class);

// protected final DOMResource resource;

/**
* Make a new {@link XPathNormalizer} for a {@link DOMResource}.
* {@inheritDoc}
*/
public XPathNormalizer() {}
public XPathNormalizer(XPathCompiler xPathCompiler, String xpath) {
super(xPathCompiler, xpath);
}

/**
* Normalize an XPath Selector refined by an RFC5147 character
Expand All @@ -78,18 +76,19 @@ public List<XPathRefinedByRFC5147CharScheme> rewrite(
getTextNodeAtPosition(resource, point.getXPath(), point.getChar(), config.getMode());
String normalizedXPath = getNormalizedXPath(resource, textNode.getLeft(), config.getEscaped());
XdmNode normalizedNode = getNode(resource, unespace(normalizedXPath));
Integer normalizedPos = posInNormalizedNode(textNode.getLeft(), textNode.getRight(), normalizedNode);
int normalizedPos = posInNormalizedNode(textNode.getLeft(), textNode.getRight(), normalizedNode);
return List.of(new XPathRefinedByRFC5147CharScheme(normalizedXPath, normalizedPos));
}

/**
* This abstract method must be implemented by normalizers. It
* returns the normalized path to the node given as argument.
*
* @param node an {@link XdmNode} to which the normlized path must be generated to
* @param escaped whether or not the normalized XPath is to be escaped for X-processing, e.g., <code>'</code> escaped to <code>&amp;apos;</code>.
* @param node an {@link XdmNode} to which the normalized path must be generated to
* @param escaped whether or not the normalized XPath is to be escaped for X-processing, e.g.,
* <code>'</code> escaped to <code>&amp;apos;</code>.
* @return the normalized XPath expression as a String
* @see XPathNormalizer#getTextNodeAtPosition(String, int, boolean)
* @see XPathRewriterBase#getTextNodeAtPosition(S9ApiResource, String, int, Mode)
*/
protected abstract String getNormalizedXPath(DOMResource resource, XdmNode node, boolean escaped)
throws SelectorException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import de.wwu.scdh.annotation.selection.*;
import de.wwu.scdh.annotation.selection.resource.DOMResource;
import de.wwu.scdh.annotation.selection.resource.S9ApiResource;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XdmNode;

/**
Expand All @@ -10,14 +12,14 @@
* context node in question.<P>
*
* The context item on which the XPath will be evaluated, is
* determined by {@link XPathNormalizer#getTextNodeAtPosition(String, int,boolean)}.
* determined by {@link XPathRewriterBase#getTextNodeAtPosition(S9ApiResource, String, int, Mode)}.
* This is generally a text node.
*/
public class XPathNormalizerWithXPath extends XPathNormalizer {

/**
* An XPath expression suitable for normalizing path expressions
* to nodes.<P>
* to nodes.<P/>
*
* Generates a path expression using the <code>path(.)</code>
* XPath function. This result in a path expression stepping from
Expand All @@ -26,6 +28,13 @@ public class XPathNormalizerWithXPath extends XPathNormalizer {
*/
public static final String PATH_FUNCTION_XPATH = "path(.)";

/**
* {@inheritDoc}
*/
public XPathNormalizerWithXPath(XPathCompiler xPathCompiler, String xpath) {
super(xPathCompiler, xpath);
}

/**
* An XPath expression suitable for normalizing path expressions
* to nodes.<P>
Expand All @@ -35,7 +44,7 @@ public class XPathNormalizerWithXPath extends XPathNormalizer {
* notation.
*/
public static final String FROM_ROOT_CLARK_XPATH =
"let $ctx:=., $elsteps:=$ctx/ancestor-or-self::element(), $txtstep:=$ctx[self::text()] return ($elsteps ! (let $step:=., $ns:=namespace-uri($step), $name:=name($step), $pos:=count($step/preceding-sibling::node()[name() eq $name])+1 return concat('/Q{', $ns, '}', $name, '[', $pos, ']')), $txtstep ! (concat('/text()[', count($txtstep/preceding-sibling::text())+1, ']'))) => string-join('')";
"let $ctx:=., $elSteps:=$ctx/ancestor-or-self::element(), $txtStep:=$ctx[self::text()] return ($elSteps ! (let $step:=., $ns:=namespace-uri($step), $name:=name($step), $pos:=count($step/preceding-sibling::node()[name() eq $name])+1 return concat('/Q{', $ns, '}', $name, '[', $pos, ']')), $txtStep ! (concat('/text()[', count($txtStep/preceding-sibling::text())+1, ']'))) => string-join('')";

/**
* An XPath expression suitable for normalizing path expressions
Expand All @@ -46,31 +55,14 @@ public class XPathNormalizerWithXPath extends XPathNormalizer {
* node. Element names are QNames in Clark notation.
*/
public static final String FROM_DEEPEST_ID_CLARK_XPATH =
"let $ctx:=., $elsteps:=$ctx/ancestor-or-self::element(), $ids:=for $step in 1 to count($elsteps) return if ($elsteps[$step]/@xml:id) then $step else -1, $idat:=$ids[. ne -1][last()], $idstep:=if ($idat) then concat('id(&apos;', $elsteps[$idat]/@xml:id, '&apos;)') else '', $txtstep:=$ctx[self::text()] return concat($idstep, ($elsteps[position() gt $idat or empty($idat)] ! (let $step:=., $ns:=namespace-uri($step), $name:=name($step), $pos:=count($step/preceding-sibling::node()[name() eq $name])+1 return concat('/Q{', $ns, '}', $name, '[', $pos, ']')), $txtstep ! (concat('/text()[', count($txtstep/preceding-sibling::text())+1, ']'))) => string-join(''))";

protected final String xpath;

/**
* Create a new {@link XPathNormalizerWithXPath} normalizer for a
* {@link DOMResource}.
*
* @param xpath an XPath expression which will be evaluated on a context node for normalization
*/
public XPathNormalizerWithXPath(String xpath) {
super();
this.xpath = xpath;
}
"let $ctx:=., $elSteps:=$ctx/ancestor-or-self::element(), $ids:=for $step in 1 to count($elSteps) return if ($elSteps[$step]/@xml:id) then $step else -1, $idAt:=$ids[. ne -1][last()], $idStep:=if ($idAt) then concat('id(&apos;', $elSteps[$idAt]/@xml:id, '&apos;)') else '', $txtStep:=$ctx[self::text()] return concat($idStep, ($elSteps[position() gt $idAt or empty($idAt)] ! (let $step:=., $ns:=namespace-uri($step), $name:=name($step), $pos:=count($step/preceding-sibling::node()[name() eq $name])+1 return concat('/Q{', $ns, '}', $name, '[', $pos, ']')), $txtStep ! (concat('/text()[', count($txtStep/preceding-sibling::text())+1, ']'))) => string-join(''))";

/**
* Get the path to the {@link XdmNode} given as parameter by using
* the XPath expressing the normalizer was initialized with.
*/
@Override
protected String getNormalizedXPath(DOMResource resource, XdmNode node, boolean escaped) throws SelectorException {
return pathExpressionWithXPath(getXPath(), node, escaped, resource.getProcessor());
}

public String getXPath() {
return xpath;
return pathExpressionWithXPath(getXPath(), node, escaped);
}
}
Loading