-
Notifications
You must be signed in to change notification settings - Fork 6
[bugfix] fn:transform() now logs xsl:message output #235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop-7.x.x
Are you sure you want to change the base?
Changes from all commits
e9189b9
933b1be
54d93bc
efb9abe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,7 @@ | |
| import net.sf.saxon.s9api.*; | ||
| import net.sf.saxon.serialize.SerializationProperties; | ||
| import net.sf.saxon.trans.UncheckedXPathException; | ||
| import java.io.StringWriter; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
| import org.exist.dom.QName; | ||
|
|
@@ -67,8 +68,10 @@ | |
| import org.w3c.dom.Node; | ||
|
|
||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
| import javax.xml.transform.ErrorListener; | ||
| import javax.xml.transform.Source; | ||
| import javax.xml.transform.SourceLocator; | ||
| import javax.xml.transform.TransformerException; | ||
| import javax.xml.transform.dom.DOMSource; | ||
| import java.net.URI; | ||
|
|
@@ -161,6 +164,7 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro | |
| } | ||
|
|
||
| final Xslt30Transformer xslt30Transformer = xsltExecutable.load30(); | ||
| xslt30Transformer.setMessageListener(new XsltMessageListener(context)); | ||
|
|
||
| options.initialMode.ifPresent(qNameValue -> xslt30Transformer.setInitialMode(Convert.ToSaxon.of(qNameValue.getQName()))); | ||
| xslt30Transformer.setInitialTemplateParameters(options.templateParams, false); | ||
|
|
@@ -532,4 +536,54 @@ public PendingException(String message, Throwable cause) { | |
| super(message, cause); | ||
| } | ||
| } | ||
|
|
||
| private static class XsltMessageListener implements MessageListener{ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please always put a space character before the opening curly brace, e.g. |
||
|
|
||
| private final XQueryContext context; | ||
|
|
||
| public XsltMessageListener(final XQueryContext context){ | ||
| this.context = context; | ||
| } | ||
|
|
||
| public void message(XdmNode content, boolean terminate, SourceLocator locator){ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All variables and parameters should be marked |
||
|
|
||
| try{ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of |
||
| final StringWriter writer = new StringWriter(); | ||
| final Serializer serializer = context.getBroker().getBrokerPool().getSaxonProcessor().newSerializer(); | ||
| serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes"); | ||
| serializer.setOutputWriter(writer); | ||
| serializer.serializeNode(content); | ||
|
|
||
| @Nullable | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please reformat from: @Nullable
final String source;to: @Nullable final String source; |
||
| final String source; | ||
| final int sourceLine; | ||
| final int sourceColumn; | ||
| if (locator != null){ | ||
| source = locator.getSystemId(); | ||
| sourceLine = locator.getLineNumber(); | ||
| sourceColumn = locator.getColumnNumber(); | ||
| } else{ | ||
| source = null; | ||
| sourceLine = -1; | ||
| sourceColumn = -1; | ||
| } | ||
|
|
||
| String tag = "<xsl:message terminate=\"" + terminate + "\""; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a |
||
| if (source != null) { | ||
| tag += " source=\"" + source + "\""; | ||
| } | ||
| if (sourceLine != -1) { | ||
| tag += " sourceLine=\"" + sourceLine + "\""; | ||
| tag += " sourceColumn=\"" + sourceColumn + "\""; | ||
| } | ||
| tag += ">"; | ||
|
|
||
| LOGGER.info("{}{}</xsl:message>", tag, writer.toString()); | ||
| } catch (final SaxonApiException e) { | ||
| LOGGER.error("Unable to serialize xsl:message content", e); | ||
| } | ||
|
|
||
|
|
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,12 @@ | |
| package org.exist.xquery.functions.fn.transform; | ||
|
|
||
| import com.evolvedbinary.j8fu.tuple.Tuple2; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.core.LogEvent; | ||
| import org.apache.logging.log4j.core.Logger; | ||
| import org.apache.logging.log4j.core.appender.AbstractAppender; | ||
| import org.apache.logging.log4j.core.config.Property; | ||
| import org.apache.logging.log4j.core.layout.PatternLayout; | ||
| import org.exist.EXistException; | ||
| import org.exist.collections.Collection; | ||
| import org.exist.security.PermissionDeniedException; | ||
|
|
@@ -49,7 +55,10 @@ | |
|
|
||
| import javax.xml.transform.Source; | ||
| import java.io.IOException; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.concurrent.CopyOnWriteArrayList; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove |
||
|
|
||
| import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; | ||
| import static org.junit.Assert.*; | ||
|
|
@@ -247,6 +256,45 @@ public void identityMixedMemoryAndPersistentDom() throws XPathException, Permiss | |
| expectQuery(IDENTITY_MIXED_XSLT_QUERY_5, expected); | ||
| } | ||
|
|
||
| @Test | ||
| public void xslMessageIsLogged() throws EXistException, PermissionDeniedException, IOException, XPathException { | ||
| final CapturingAppender appender = new CapturingAppender(); | ||
| appender.start(); | ||
|
|
||
| final Logger transformLogger = (Logger) LogManager.getLogger(Transform.class); | ||
| transformLogger.addAppender(appender); | ||
|
|
||
| try { | ||
| final String query = | ||
| "fn:transform(map {\n" + | ||
| " \"stylesheet-text\": '<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"2.0\">\n" + | ||
| " <xsl:template match=\"/\">\n" + | ||
| " <xsl:message>Hello from XSLT</xsl:message>\n" + | ||
| " </xsl:template>\n" + | ||
| " </xsl:stylesheet>',\n" + | ||
| " \"source-node\": document { <in/> }\n" + | ||
| "})?output"; | ||
|
|
||
| final BrokerPool pool = existEmbeddedServer.getBrokerPool(); | ||
| try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject())); | ||
| final XQueryUtil.QueryResult queryResult = XQueryUtil.query(broker, new StringSource(query), false, null, null, null, null, null)) { | ||
| assertNotNull(queryResult.result); | ||
| } | ||
|
|
||
| String logged = null; | ||
| for (final String message : appender.getMessages()) { | ||
| if (message.contains("<xsl:message")) { | ||
| logged = message; | ||
| break; | ||
| } | ||
| } | ||
| assertNotNull("Expected an xsl:message log entry", logged); | ||
| assertTrue(logged.contains("Hello from XSLT")); | ||
| } finally { | ||
| transformLogger.removeAppender(appender); | ||
| } | ||
| } | ||
|
|
||
| private static void expectQuery(final String query, final Source expected) throws EXistException, XPathException, PermissionDeniedException, IOException { | ||
| final BrokerPool pool = existEmbeddedServer.getBrokerPool(); | ||
| try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject())); | ||
|
|
@@ -298,4 +346,23 @@ private static void createCollection(final DBBroker broker, final Txn transactio | |
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| private static class CapturingAppender extends AbstractAppender { | ||
|
|
||
| private final List<String> messages = new ArrayList<>(); | ||
|
|
||
| CapturingAppender() { | ||
| super("capturing-appender", null, PatternLayout.createDefaultLayout(), false, Property.EMPTY_ARRAY); | ||
| } | ||
|
|
||
| @Override | ||
| public void append(final LogEvent event) { | ||
| messages.add(event.getMessage().getFormattedMessage()); | ||
| } | ||
|
|
||
| List<String> getMessages() { | ||
| return messages; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of passing in
contextjust pass in the Saxon Processor, i.e.context.getBroker().getBrokerPool().getSaxonProcessor()