diff --git a/cli/src/main/java-templates/AbstractNormalize.java b/cli/src/main/java-templates/AbstractNormalize.java index 8e4ae9e..277603c 100644 --- a/cli/src/main/java-templates/AbstractNormalize.java +++ b/cli/src/main/java-templates/AbstractNormalize.java @@ -156,7 +156,7 @@ protected NormalizerFactory getNormalizerFactory() { } protected RewriterConfig getRewriterConfig() throws CliException { - return new RewriterConfig(mode, false, getNormalizerXPath(), true); + return new RewriterConfig(mode, false, getNormalizerXPath(), true, true); } } diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/RewriterConfig.java b/core/src/main/java/de/wwu/scdh/annotation/selection/RewriterConfig.java index e2761f1..124e072 100644 --- a/core/src/main/java/de/wwu/scdh/annotation/selection/RewriterConfig.java +++ b/core/src/main/java/de/wwu/scdh/annotation/selection/RewriterConfig.java @@ -10,6 +10,7 @@ public class RewriterConfig { private final boolean escaped; private final String xpath; private final boolean rewritesTraceLeaf; + private final boolean removeEmptyNamespaces; /** * Make a new {@link RewriterConfig}. @@ -19,19 +20,23 @@ public class RewriterConfig { * @param xpath an XPath expression which will be evaluated on the context node for normalization * @param rewritesTraceLeaf - whether a Q{http://wwu.de/scdh/selection-engine/node-tracing}text * segment has to be rewritten with text() + * @param removeEmptyNamespaces - whether a Q{} in a path expression (XPath segment) is to be removed. */ - public RewriterConfig(Mode mode, boolean escaped, String xpath, boolean rewritesTraceLeaf) { + public RewriterConfig( + Mode mode, boolean escaped, String xpath, boolean rewritesTraceLeaf, boolean removeEmptyNamespaces) { this.mode = mode; this.escaped = escaped; this.xpath = xpath; this.rewritesTraceLeaf = rewritesTraceLeaf; + this.removeEmptyNamespaces = removeEmptyNamespaces; } /** * Clone the {@link RewriterConfig}, but set a new {@link Mode}. */ public static RewriterConfig withMode(RewriterConfig config, Mode mode) { - return new RewriterConfig(mode, config.escaped, config.xpath, config.rewritesTraceLeaf); + return new RewriterConfig( + mode, config.escaped, config.xpath, config.rewritesTraceLeaf, config.removeEmptyNamespaces); } public Mode getMode() { @@ -49,4 +54,8 @@ public String getXPath() { public boolean rewritesTraceLeaf() { return rewritesTraceLeaf; } + + public boolean removeEmptyNamespaces() { + return removeEmptyNamespaces; + } } diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRefinedByRFC5147CharSchemeForwardMapper.java b/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRefinedByRFC5147CharSchemeForwardMapper.java index 465dc66..ad3876a 100644 --- a/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRefinedByRFC5147CharSchemeForwardMapper.java +++ b/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRefinedByRFC5147CharSchemeForwardMapper.java @@ -68,7 +68,7 @@ public List rewrite( getNode(preimage.getImage().getContents(), unespace(normalizedXPath), preimage.getProcessor()); Integer normalizedPos = posInNormalizedNode(imageNode, preimagePair.getRight(), normalizedNode); transformed.add( - new XPathRefinedByRFC5147CharScheme(replaceTraceTextLeaf(normalizedXPath, config), normalizedPos)); + new XPathRefinedByRFC5147CharScheme(postProcForwardPaths(normalizedXPath, config), normalizedPos)); } return transformed; } diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRewriterBase.java b/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRewriterBase.java index 03fa567..5a39333 100644 --- a/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRewriterBase.java +++ b/core/src/main/java/de/wwu/scdh/annotation/selection/rewriter/XPathRewriterBase.java @@ -41,12 +41,22 @@ public abstract class XPathRewriterBase { public static Pattern TEXT_LEAF = Pattern.compile("text\\(\\)\\[(\\d+)]$"); + public static final Pattern EMPTY_NAMESPACE = Pattern.compile("Q\\{}"); + public static String replaceTraceTextLeaf(String xpath) { Matcher matcher = TRACE_TEXT_LEAF.matcher(xpath); return matcher.replaceAll("text()[$1]"); } - public static String replaceTraceTextLeaf(String xpath, RewriterConfig config) { + public static String replaceEmptyNamespace(String xpath) { + Matcher matcher = EMPTY_NAMESPACE.matcher(xpath); + return matcher.replaceAll(""); + } + + public static String postProcForwardPaths(String xpath, RewriterConfig config) { + if (config.removeEmptyNamespaces()) { + xpath = replaceEmptyNamespace(xpath); + } if (config.rewritesTraceLeaf()) { return replaceTraceTextLeaf(xpath); } else { @@ -77,7 +87,7 @@ public XPathRewriterBase() {} /** * This method run the first stage of the normalization * process. It gets the node where the pair of XPath and position - * of an character-scheme-refined XPath selector points to. Either + * of a character-scheme-refined XPath selector points to. Either * this node is a text node, or the selector is invalid in the * context of the current document. In general, the resulting * position is not the same as the input position.

@@ -95,8 +105,8 @@ public XPathRewriterBase() {} * @param resource the {@link DOMResource} on the base of which the normalization is done * @param xpath the XPath part of the XPath selector * @param position the position following the character scheme of RFC5147 - * @param mode an normalization algorithm selected from {@link Mode} - * @throws {@link SelectorException} + * @param mode a normalization algorithm selected from {@link Mode} + * @throws SelectorException if the XPath does not select exactly one node * @return a pair of node and position */ protected Pair getTextNodeAtPosition( @@ -117,7 +127,7 @@ protected Pair getTextNodeAtPosition( } /** - * The implementation of step 1 of the normalization algorithm in + * The implementation of step 1 of the normalization algorithm * in mode {@link Mode#FIRST}. */ protected final Pair getFirstNodeAtPosition( @@ -132,7 +142,7 @@ protected final Pair getFirstNodeAtPosition( } /** - * The implementation of step 1 of the normalization algorithm in + * The implementation of step 1 of the normalization algorithm * in mode {@link Mode#SECOND}. */ protected final Pair getSecondNodeAtPosition( @@ -149,7 +159,7 @@ protected final Pair getSecondNodeAtPosition( } /** - * The implementation of step 1 of the normalization algorithm in + * The implementation of step 1 of the normalization algorithm * in mode {@link Mode#FIRST_OF_DEEPEST_NODES}. */ protected final Pair getFirstOfDeepestNodesAtPosition( @@ -162,7 +172,8 @@ protected final Pair getFirstOfDeepestNodesAtPosition( return nodesAtPosition.get(0); } else { // we still have to get the text node with the deepest path - LOG.debug("found {} nodes, getting deepest", nodesAtPosition.size()); + LOG.debug( + "found {} nodes, getting deepest (get first of deepest nodes at position)", nodesAtPosition.size()); // note, that Stream.max() returns the first of the items with the maximum value Optional> deepest = nodesAtPosition.stream().max(Comparator.comparing(XPathNormalizer::getDepth)); @@ -171,7 +182,7 @@ protected final Pair getFirstOfDeepestNodesAtPosition( } /** - * The implementation of step 1 of the normalization algorithm in + * The implementation of step 1 of the normalization algorithm * in mode {@link Mode#LAST_OF_DEEPEST_NODES}. */ protected final Pair getLastOfDeepestNodesAtPosition( @@ -200,7 +211,7 @@ protected final Pair getLastOfDeepestNodesAtPosition( * @param resource the {@link DOMResource} on the base of which the normalization is done * @param xpath the XPath part of the XPath selector * @param position the position following the character scheme of RFC5147 - * @throws {@link SelectorException} + * @throws SelectorException if xpath does not evaluate to one node * @return a pair of node and position */ protected final Pair getDeepTextNodeAtPositionStopAtEnd( @@ -221,7 +232,7 @@ protected final Pair getDeepTextNodeAtPositionStopAtEnd( * @param resource the {@link DOMResource} on the base of which the normalization is done * @param xpath the XPath part of the XPath selector * @param position the position following the character scheme of RFC5147 - * @throws {@link SelectorException} + * @throws SelectorException if xpath does not get one node * @return a pair of node and position */ protected final Pair getDeepTextNodeAtPositionStepOverEnd( @@ -238,7 +249,7 @@ protected final Pair getDeepTextNodeAtPositionStepOverEnd( } /** - * Get the node from the DOM resource given by the the XPath + * Get the node from the DOM resource given by the XPath * passed as argument. If the XPath does not evaluate to a single * node, this method raises an {@link SelectorException}. * @@ -257,10 +268,8 @@ protected final XdmNode getNode(DOMResource resource, String xpath) throws Selec // assert that the XPath selects exactly 1 node if (nodes.size() != 1) { LOG.error("XPath '{}' does not select exactly one node: selects {} nodes", xpath, nodes.size()); - throw new SelectorException("XPath '" + xpath - + "' does not select exactly one node: selects " - + String.valueOf(nodes.size()) - + " nodes"); + throw new SelectorException( + "XPath '" + xpath + "' does not select exactly one node: selects " + nodes.size() + " nodes"); } else if (!nodes.itemAt(0).isNode()) { LOG.error("Node selected by XPath '{}' does not select a node", xpath); throw new SelectorException("XPath '" + xpath + "' does not select a node"); @@ -274,7 +283,7 @@ protected final XdmNode getNode(DOMResource resource, String xpath) throws Selec } /** - * Get the node from the XDM value resource given by the the XPath + * Get the node from the XDM value resource given by the XPath * passed as argument. If the XPath does not evaluate to a single * node, this method raises an {@link SelectorException}. * @@ -287,7 +296,7 @@ protected final XdmNode getNode(XdmValueResource resource, String xpath) throws } /** - * Get the node from the DOM resource given by the the XPath + * Get the node from the DOM resource given by the XPath * passed as argument. If the XPath does not evaluate to a single * node, this method raises an {@link SelectorException}. */ @@ -303,13 +312,13 @@ protected final XdmNode getNode(XdmValue value, String xpath, Processor processo } if (result.size() != 1) { LOG.error( - "XPath '{}' does not select exaclty one node in XdmValueResource: selects {} nodes", + "XPath '{}' does not select exactly one node in XdmValueResource: selects {} nodes", xpath, result.size()); throw new SelectorException( "XPath '" + xpath + "' does not select exactly one node in XdmValueResource"); } else if (!result.itemAt(0).isNode()) { - LOG.error("XPath '{}' does not select a node", xpath, result.size()); + LOG.error("XPath '{}' does not select a node", xpath); throw new SelectorException("XPath '" + xpath + "' does not select a node"); } else { return (XdmNode) result.itemAt(0); @@ -326,7 +335,7 @@ protected final XdmNode getNode(XdmValue value, String xpath, Processor processo * a node and a position, that contain the character scheme * position inside a given fragment.

* - * This method collects all canditates in case of referential + * This method collects all candidates in case of referential * ambiguity. See {@link Mode}. * * @param fragment as {@link XdmNode} inside a {@link DOMResource} @@ -336,7 +345,7 @@ protected final List> getDescendantTextNodesWithPosition( Iterator descendants = fragment.axisIterator(Axis.DESCENDANT_OR_SELF); int charsEaten = 0; XdmNode node = fragment; - List> nodesAtPosition = new ArrayList>(); + List> nodesAtPosition = new ArrayList<>(); while (descendants.hasNext()) { node = descendants.next(); LOG.debug("investigating '{}' node", node.getUnderlyingNode().getLocalPart()); @@ -347,7 +356,7 @@ protected final List> getDescendantTextNodesWithPosition( charsEaten += length; } else { // position is inside this text node or at its end - nodesAtPosition.add(new ImmutablePair(node, position - charsEaten)); + nodesAtPosition.add(new ImmutablePair<>(node, position - charsEaten)); if (position < charsEaten + length) { // we can stop, since positions in all further text nodes will have greater positions break; @@ -367,14 +376,14 @@ protected final List> getDescendantTextNodesWithPosition( * position inside a given fragment, or in the first text node * before or after it.

* - * This method collects all canditates in case of referential + * This method collects all candidates in case of referential * ambiguity. See {@link Mode}. * * @param fragment as {@link XdmNode} inside a {@link DOMResource} * @param position the RFC 5147 character scheme position inside the fragment */ protected final List> getTextNodesWithPosition(final XdmNode fragment, final int position) { - List> nodesAtPosition = new ArrayList>(); + List> nodesAtPosition = new ArrayList<>(); XdmNode node; // 1. before the fragment, if position is zero if (position == 0) { @@ -386,7 +395,7 @@ protected final List> getTextNodesWithPosition(final XdmN textNodeSeen = true; int length = node.getUnderlyingValue().getUnicodeStringValue().length32(); - nodesAtPosition.add(new ImmutablePair(node, length)); + nodesAtPosition.add(new ImmutablePair<>(node, length)); } } } @@ -404,7 +413,7 @@ protected final List> getTextNodesWithPosition(final XdmN charsEaten += length; } else { // position is inside this text node or at its end - nodesAtPosition.add(new ImmutablePair(node, position - charsEaten)); + nodesAtPosition.add(new ImmutablePair<>(node, position - charsEaten)); if (position < charsEaten + length) { // we can stop, since positions in all further text nodes will have greater positions break; @@ -422,7 +431,7 @@ protected final List> getTextNodesWithPosition(final XdmN node = following.next(); if (node.getNodeKind().equals(XdmNodeKind.TEXT)) { textNodeSeen = true; - nodesAtPosition.add(new ImmutablePair(node, 0)); + nodesAtPosition.add(new ImmutablePair<>(node, 0)); } } } @@ -433,7 +442,6 @@ protected final List> getTextNodesWithPosition(final XdmN * Get the new position value based on the old one and the * fragment selected by the normalized XPath. * - * @param resource the {@link DOMResource} operating on * @param textNode the text node as {@link XdmNode} gotten from step 1 * @param pos the position gotten form step 1 * @param fragment the {@link XdmNode} selected by the XPath resulting from step 2 @@ -446,9 +454,9 @@ protected int posInNormalizedNode(XdmNode textNode, int pos, XdmNode fragment) t // iter over all descendant text nodes until we found textNode boolean found = false; int posAcc = pos; - Iterator descenant = fragment.axisIterator(Axis.DESCENDANT); - while (descenant.hasNext() && !found) { - XdmNode node = descenant.next(); + Iterator descendant = fragment.axisIterator(Axis.DESCENDANT); + while (descendant.hasNext() && !found) { + XdmNode node = descendant.next(); if (!node.getNodeKind().equals(XdmNodeKind.TEXT)) continue; if (node.equals(textNode)) { found = true; @@ -479,17 +487,17 @@ protected Pair reportNotFound(String xpath, int position) thro * its ancestors. */ protected static int getDepth(XdmNode node) { - Iterator ascendents = node.axisIterator(Axis.ANCESTOR_OR_SELF); + Iterator ancestors = node.axisIterator(Axis.ANCESTOR_OR_SELF); int depth = 0; - while (ascendents.hasNext()) { + while (ancestors.hasNext()) { depth += 1; - ascendents.next(); + ancestors.next(); } return depth; } /** - * A utiltity method that gets the depth of a node of a pair of + * A utility method that gets the depth of a node of a pair of * node and position like used in this module. */ protected static int getDepth(Pair pair) { @@ -497,7 +505,7 @@ protected static int getDepth(Pair pair) { } /** - * A utility function for unescaping XPaths. + * A utility function for un-escaping XPaths. */ protected String unespace(String in) { return in.replace("'", "'"); @@ -511,7 +519,7 @@ protected String unespace(String in) { * * @param xpath the XPath for generating a path expression, e.g., fn:xpath() * @param node the {@link XdmNode} for which to generate the path expression - * @param escaped whether or not the generated path expression is to be escaped + * @param escaped whether the generated path expression is to be escaped * @param processor a Saxon {@link Processor} */ protected String pathExpressionWithXPath(String xpath, XdmNode node, boolean escaped, Processor processor) @@ -524,17 +532,17 @@ protected String pathExpressionWithXPath(String xpath, XdmNode node, boolean esc selector.setContextItem(node); nodes = selector.evaluate(); } catch (SaxonApiException e) { - LOG.error("failed to normalize XPath using '{}': ", xpath, e.getMessage()); + LOG.error("failed to normalize XPath using '{}': ", xpath); throw new SelectorException(e); } if (nodes.size() != 1) { LOG.error("normalizing XPath '{}' did not return exactly one item: returned {} items", xpath, nodes.size()); throw new SelectorException("normalizing XPath '" + xpath + "' did not return exactly one item: returned " - + String.valueOf(nodes.size()) + + nodes.size() + " item"); } else if (!nodes.itemAt(0).isAtomicValue()) { - LOG.error("normalizing XPath '{}' did not return an atomic value", xpath, nodes.size()); + LOG.error("normalizing XPath '{}' did not return an atomic value", xpath); throw new SelectorException("normalizing XPath '" + xpath + "' did not return an atomic value"); } else { if (escaped) { diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathNormalizerWithXPath.java b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathNormalizerWithXPath.java index 507b036..2d437a7 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathNormalizerWithXPath.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathNormalizerWithXPath.java @@ -23,7 +23,7 @@ public class TestXPathNormalizerWithXPath { public static final URI GESANG_HTML = new File(TEST_DIR, "Gesang.tei.html").toURI(); public static final URI GESANG_XML = new File(TEST_DIR, "Gesang.tei.xml").toURI(); - RewriterConfig config = new RewriterConfig(null, false, null, false); + RewriterConfig config = new RewriterConfig(null, false, null, false, false); @Test public void testWithPathFunction() throws SelectorException, SaxonApiException, IOException { diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeBackwardMapper.java b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeBackwardMapper.java index 603ad71..0865e03 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeBackwardMapper.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeBackwardMapper.java @@ -1,6 +1,5 @@ package de.wwu.scdh.annotation.selection.rewriter; -import static org.hamcrest.CoreMatchers.*; import static org.junit.jupiter.api.Assertions.*; import de.wwu.scdh.annotation.selection.*; @@ -33,10 +32,15 @@ public class TestXPathRefinedByRFC5147CharSchemeBackwardMapper { public static final File ID_XSL = Paths.get("src", "test", "resources", "xsl", "id.xsl").toFile(); - public static final File TEXT_WITH_TOC_XSL = - Paths.get("src", "test", "resources", "xsl", "text-with-toc.xsl").toFile(); + public static final File TEXT_WITH_TOC_XHTML_XSL = Paths.get( + "src", "test", "resources", "xsl", "text-with-toc-xhtml.xsl") + .toFile(); - RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false); + public static final File TEXT_WITH_TOC_HTML_XSL = Paths.get( + "src", "test", "resources", "xsl", "text-with-toc-html.xsl") + .toFile(); + + RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false, false); public static XdmValue transform(DOMResource resource, File stylesheet, File pkg) throws SaxonApiException { XsltCompiler compiler = PROC.newXsltCompiler(); @@ -127,7 +131,7 @@ public void testBackwardToCNode() throws ResourceException, SaxonApiException, S DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); MappedDOMResource preimage = new MappedDOMResource(source); XdmValueResource image = - new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XSL, LIBTRACE_XML), PROC); + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XHTML_XSL, LIBTRACE_XML), PROC); preimage.setImage(image); XPathRefinedByRFC5147CharSchemeBackwardMapper mapper = new XPathRefinedByRFC5147CharSchemeBackwardMapper("path(.)"); @@ -149,7 +153,49 @@ public void testBackwardHeadNode() throws ResourceException, SaxonApiException, DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); MappedDOMResource preimage = new MappedDOMResource(source); XdmValueResource image = - new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XSL, LIBTRACE_XML), PROC); + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XHTML_XSL, LIBTRACE_XML), PROC); + preimage.setImage(image); + XPathRefinedByRFC5147CharSchemeBackwardMapper mapper = + new XPathRefinedByRFC5147CharSchemeBackwardMapper("path(.)"); + List mapped = mapper.rewrite(preimage, imagePoint, config); + assertEquals(1, mapped.size()); + assertEquals( + "/Q{http://www.tei-c.org/ns/1.0}TEI[1]/Q{http://www.tei-c.org/ns/1.0}text[1]/Q{http://www.tei-c.org/ns/1.0}body[1]/Q{http://www.tei-c.org/ns/1.0}lg[1]/Q{http://www.tei-c.org/ns/1.0}head[1]/text()[1]", + mapped.get(0).getXPath()); + assertEquals(5, mapped.get(0).getChar()); + } + + @Test + public void testHtmlBackwardHeadNode() throws ResourceException, SaxonApiException, SelectorException { + // we transform a point from the H2, originating from a preimage node that occurs twice in the image + XPathRefinedByRFC5147CharScheme imagePoint = + new XPathRefinedByRFC5147CharScheme("/Q{}html[1]/Q{}body[1]/Q{}div[2]/Q{}div[1]/Q{}h2[1]", 5); + // ("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); + DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); + MappedDOMResource preimage = new MappedDOMResource(source); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_HTML_XSL, LIBTRACE_XML), PROC); + preimage.setImage(image); + XPathRefinedByRFC5147CharSchemeBackwardMapper mapper = + new XPathRefinedByRFC5147CharSchemeBackwardMapper("path(.)"); + List mapped = mapper.rewrite(preimage, imagePoint, config); + assertEquals(1, mapped.size()); + assertEquals( + "/Q{http://www.tei-c.org/ns/1.0}TEI[1]/Q{http://www.tei-c.org/ns/1.0}text[1]/Q{http://www.tei-c.org/ns/1.0}body[1]/Q{http://www.tei-c.org/ns/1.0}lg[1]/Q{http://www.tei-c.org/ns/1.0}head[1]/text()[1]", + mapped.get(0).getXPath()); + assertEquals(5, mapped.get(0).getChar()); + } + + @Test + public void testHtmlNoNsBackwardHeadNode() throws ResourceException, SaxonApiException, SelectorException { + // we transform a point from the H2, originating from a preimage node that occurs twice in the image + XPathRefinedByRFC5147CharScheme imagePoint = + new XPathRefinedByRFC5147CharScheme("/html[1]/body[1]/div[2]/div[1]/h2[1]", 5); + // ("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); + DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); + MappedDOMResource preimage = new MappedDOMResource(source); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_HTML_XSL, LIBTRACE_XML), PROC); preimage.setImage(image); XPathRefinedByRFC5147CharSchemeBackwardMapper mapper = new XPathRefinedByRFC5147CharSchemeBackwardMapper("path(.)"); diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeForwardMapper.java b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeForwardMapper.java index 83567ae..c3a76d4 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeForwardMapper.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeForwardMapper.java @@ -32,13 +32,20 @@ public class TestXPathRefinedByRFC5147CharSchemeForwardMapper { public static final File ID_XSL = Paths.get("src", "test", "resources", "xsl", "id.xsl").toFile(); - public static final File TEXT_WITH_TOC_XSL = - Paths.get("src", "test", "resources", "xsl", "text-with-toc.xsl").toFile(); + public static final File TEXT_WITH_TOC_XHTML_XSL = Paths.get( + "src", "test", "resources", "xsl", "text-with-toc-xhtml.xsl") + .toFile(); + + public static final File TEXT_WITH_TOC_HTML_XSL = Paths.get( + "src", "test", "resources", "xsl", "text-with-toc-html.xsl") + .toFile(); public static final File TEXT_XSL = Paths.get("src", "test", "resources", "xsl", "text.xsl").toFile(); - RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false); + public static final RewriterConfig CONFIG = new RewriterConfig(Mode.FIRST, false, null, false, false); + + public static final RewriterConfig CONFIG_NO_NS = new RewriterConfig(Mode.FIRST, false, null, true, true); public static XdmValue transform(DOMResource resource, File stylesheet, File pkg) throws SaxonApiException { XsltCompiler compiler = PROC.newXsltCompiler(); @@ -59,7 +66,7 @@ public void testGesangMappedWithIdentity() throws ResourceException, SaxonApiExc new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); XPathRefinedByRFC5147CharScheme preimagePoint = new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); - List mapped = mapper.rewrite(preimage, preimagePoint, config); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); assertEquals(1, mapped.size()); assertEquals( mapped.get(0).getXPath(), @@ -74,11 +81,12 @@ public void testForwardToMultipleNodes() throws ResourceException, SaxonApiExcep new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); MappedDOMResource preimage = new MappedDOMResource(source); - XdmValueResource image = new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XSL, LIBTRACE_XML)); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XHTML_XSL, LIBTRACE_XML)); preimage.setImage(image); XPathRefinedByRFC5147CharSchemeForwardMapper mapper = new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); - List mapped = mapper.rewrite(preimage, preimagePoint, config); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); assertEquals(2, mapped.size()); assertEquals( @@ -109,14 +117,55 @@ public void testForwardToZeroNodes() throws ResourceException, SaxonApiException "/*:TEI[1]/*:teiHeader[1]/*:fileDesc[1]/*:titleStmt[1]/*:author[1]", 5); DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); MappedDOMResource preimage = new MappedDOMResource(source); - XdmValueResource image = new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XSL, LIBTRACE_XML)); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_XHTML_XSL, LIBTRACE_XML)); preimage.setImage(image); XPathRefinedByRFC5147CharSchemeForwardMapper mapper = new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); - List mapped = mapper.rewrite(preimage, preimagePoint, config); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); assertEquals(0, mapped.size()); } + @Test + public void testHtmlForwardToOneNode() throws ResourceException, SaxonApiException, SelectorException { + // we transform a point that occurs twice in the output + XPathRefinedByRFC5147CharScheme preimagePoint = + new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:l[2]/text()[2]", 7); + DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); + MappedDOMResource preimage = new MappedDOMResource(source); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_HTML_XSL, LIBTRACE_XML)); + preimage.setImage(image); + XPathRefinedByRFC5147CharSchemeForwardMapper mapper = + new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); + assertEquals(1, mapped.size()); + assertEquals( + "/Q{}html[1]/Q{}body[1]/Q{}div[2]/Q{}div[1]/Q{}p[2]/Q{http://wwu.de/scdh/selection-engine/node-tracing}text[2]", + mapped.get(0).getXPath(), + "fn:path returns QNames for elements on the '' namespace as Q{}*."); + } + + @Test + public void testHtmlNoNsForwardToOneNode() throws ResourceException, SaxonApiException, SelectorException { + // we transform a point that occurs twice in the output + XPathRefinedByRFC5147CharScheme preimagePoint = + new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:l[2]/text()[2]", 7); + DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); + MappedDOMResource preimage = new MappedDOMResource(source); + XdmValueResource image = + new XdmValueResource(GESANG_XML, transform(source, TEXT_WITH_TOC_HTML_XSL, LIBTRACE_XML)); + preimage.setImage(image); + XPathRefinedByRFC5147CharSchemeForwardMapper mapper = + new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG_NO_NS); + assertEquals(1, mapped.size()); + assertEquals( + "/html[1]/body[1]/div[2]/div[1]/p[2]/text()[2]", + mapped.get(0).getXPath(), + "configured to return nice path expressions into HTML"); + } + @Test public void testTextToOneNode() throws ResourceException, SaxonApiException, SelectorException { DOMResource source = DOMResource.fromXMLwithXerces(GESANG_XML, PROC); @@ -127,7 +176,7 @@ public void testTextToOneNode() throws ResourceException, SaxonApiException, Sel new XPathRefinedByRFC5147CharSchemeForwardMapper("path(.)"); XPathRefinedByRFC5147CharScheme preimagePoint = new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); - List mapped = mapper.rewrite(preimage, preimagePoint, config); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); assertEquals(1, mapped.size()); // the XdmValue output looks a bit weird: all text containers are directly in document node assertTrue(mapped.get(0).getXPath().endsWith("/Q{http://wwu.de/scdh/selection-engine/node-tracing}text[22]")); @@ -145,7 +194,7 @@ public void testTextToOneNodeWithRootOffset() throws ResourceException, SaxonApi "path(ancestor-or-self::node()[ parent::node()[not(parent::node())] ]) "); XPathRefinedByRFC5147CharScheme preimagePoint = new XPathRefinedByRFC5147CharScheme("/*:TEI[1]/*:text[1]/*:body[1]/*:lg[1]/*:head[1]", 5); - List mapped = mapper.rewrite(preimage, preimagePoint, config); + List mapped = mapper.rewrite(preimage, preimagePoint, CONFIG); assertEquals(1, mapped.size()); assertTrue(mapped.get(0).getXPath().endsWith("/Q{http://wwu.de/scdh/selection-engine/node-tracing}text[22]")); assertEquals(5, mapped.get(0).getChar()); diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextBackwardMapper.java b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextBackwardMapper.java index 4c591b7..5e0cc60 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextBackwardMapper.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextBackwardMapper.java @@ -39,7 +39,7 @@ public class TestXPathRefinedByRFC5147CharSchemeToTextBackwardMapper { public static final File NO_HEADER_XSL = Paths.get("src", "test", "resources", "xsl", "text-no-header.xsl").toFile(); - RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false); + RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false, false); public static XdmValue transform(DOMResource resource, File stylesheet, File pkg) throws SaxonApiException { XsltCompiler compiler = PROC.newXsltCompiler(); diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextForwardMapper.java b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextForwardMapper.java index b41b7b4..f011835 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextForwardMapper.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/rewriter/TestXPathRefinedByRFC5147CharSchemeToTextForwardMapper.java @@ -39,7 +39,7 @@ public class TestXPathRefinedByRFC5147CharSchemeToTextForwardMapper { public static final File NO_HEADER_XSL = Paths.get("src", "test", "resources", "xsl", "text-no-header.xsl").toFile(); - RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false); + RewriterConfig config = new RewriterConfig(Mode.FIRST, false, null, false, false); public static XdmValue transform(DOMResource resource, File stylesheet, File pkg) throws SaxonApiException { XsltCompiler compiler = PROC.newXsltCompiler(); diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/wadm/TestNormalizeAnnotation.java b/core/src/test/java/de/wwu/scdh/annotation/selection/wadm/TestNormalizeAnnotation.java index 1aec7b0..027fda1 100644 --- a/core/src/test/java/de/wwu/scdh/annotation/selection/wadm/TestNormalizeAnnotation.java +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/wadm/TestNormalizeAnnotation.java @@ -60,7 +60,7 @@ public void setupResource() throws URISyntaxException, ResourceException, Malfor } private static RewriterConfig makeConfig(String xpath) { - return new RewriterConfig(null, false, xpath, false); + return new RewriterConfig(null, false, xpath, false, false); } // normalizing XPathSelector refinedBy FragmentSelector conforming to RFC5147 character scheme diff --git a/core/src/test/resources/xsl/text-with-toc-html.xsl b/core/src/test/resources/xsl/text-with-toc-html.xsl new file mode 100644 index 0000000..12ea13a --- /dev/null +++ b/core/src/test/resources/xsl/text-with-toc-html.xsl @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + <xsl:apply-templates select="//teiHeader//title"/> + + + +

+

Table of contents:

+ +
+
+
+ +
+ + + + + + +
+ + +
+
+ + +

+ + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/test/resources/xsl/text-with-toc.xsl b/core/src/test/resources/xsl/text-with-toc-xhtml.xsl similarity index 82% rename from core/src/test/resources/xsl/text-with-toc.xsl rename to core/src/test/resources/xsl/text-with-toc-xhtml.xsl index 5d893c5..131c0dc 100644 --- a/core/src/test/resources/xsl/text-with-toc.xsl +++ b/core/src/test/resources/xsl/text-with-toc-xhtml.xsl @@ -50,14 +50,21 @@ - +

- +

- + + + + + + + + @@ -71,15 +78,12 @@ - - + + - - - - - + + diff --git a/test/Gesang.html b/test/Gesang.html new file mode 100644 index 0000000..63c5bd0 --- /dev/null +++ b/test/Gesang.html @@ -0,0 +1,11 @@ +Trawr-Gesang von der noth Christi am Oelberg in dem Garten

Table of contents:

Trawr-Gesang von der noth Christi am Oelberg in dem Garten


+ +
+

Trawr-Gesang von der noth Christi am Oelberg in dem Garten

+

Bey stiller nacht zur ersten wacht

+

Ein stimm sich gund zu klagen.

+

Jch nam in acht waß die doch sagt;

+

That hin mit Augen schlagen.

+
+ +
\ No newline at end of file diff --git a/test/Gesang.xhtml b/test/Gesang.xhtml new file mode 100644 index 0000000..069ce48 --- /dev/null +++ b/test/Gesang.xhtml @@ -0,0 +1,11 @@ +Trawr-Gesang von der noth Christi am Oelberg in dem Garten

Table of contents:

Trawr-Gesang von der noth Christi am Oelberg in dem Garten


+ +
+

Trawr-Gesang von der noth Christi am Oelberg in dem Garten

+

Bey stiller nacht zur ersten wacht

+

Ein stimm sich gund zu klagen.

+

Jch nam in acht waß die doch sagt;

+

That hin mit Augen schlagen.

+
+ +
\ No newline at end of file