Skip to content

Instantly share code, notes, and snippets.

@matthias-dirickx
Created May 6, 2020 15:33
Show Gist options
  • Save matthias-dirickx/1059f415855fdca48db4140bd757973c to your computer and use it in GitHub Desktop.
Save matthias-dirickx/1059f415855fdca48db4140bd757973c to your computer and use it in GitHub Desktop.
Limited xml support with SAXON at the foundation to get xpath and xquery results for verification purposes in a test context.
/**
MIT License
Copyright (c) 2020 Matthias Dirickx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package be.mdi.test.utils;
import java.io.StringReader;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
/**
* <p>Class to support getting data from an XML string with:
* <ul>
* <li>XPath</li>
* <li>XQuery</li>
* </ul>
* </p>
* @author Matthias.Dirickx
*
*/
public class XmlSupport {
private final String XMLNS_DEFINITION_REGEX = " xmlns:.+=\".+?\"";
private final String IN_MESSAGE_NAMESPACE_REGEX = "(?:(?<=<)[^\\/]+?\\:|(?<=<\\/)[^\\/]+?\\:)";
private final String BETWEEN_TAG_WHITESPACE_REGEX = "(?<=>)\\s+(?=<)";
private String xml;
private String query;
private Processor processor;
private XdmNode saxXml;
private XdmValue saxResult;
private String result;
public boolean removeNamespaceReferences;
public boolean removeWhitespaceBetweenTags;
/**
* <p>XmlSupport constructor.</p>
* <p>Takes one argument: the XML string.</p>
* <p>Note:<br>
* The break tag (either {@code <br>} or {@code </br>} are replaced with "\n".
* </p>
*
* @param xml
* @throws SaxonApiException
*/
public XmlSupport(String xml) throws SaxonApiException {
this.xml = xml;
//Defaults
this.removeNamespaceReferences = true;
this.removeWhitespaceBetweenTags = true;
initiate();
}
/**
* Initiation method used in the constructor.
* @throws SaxonApiException
*/
private void initiate() throws SaxonApiException {
this.processor = new Processor(false);
this.saxXml = processor.newDocumentBuilder().build(new StreamSource(new StringReader(xml.replaceAll("<\\/?br>", "\n"))));
}
public XdmValue getInputXdmValue() {
return XdmNode.makeValue(saxXml);
}
public XdmValue getOutputXdmValue() {
return saxResult;
}
public static XdmValue getXdmValueForString(String xml) throws IllegalArgumentException, SaxonApiException {
return XdmNode.makeValue(new Processor(false).newDocumentBuilder().build(new StreamSource(new StringReader(xml.replaceAll("<\\/?br>", "\n")))));
}
public static String getPrettyXml(String xml) throws IllegalArgumentException, SaxonApiException {
return getXdmValueForString(xml).toString();
}
/**
* <p>Get the output as a string.</p>
* <p>This returns a string that is pretty formatted with the SAXON standard settings.</p>
*
* @return String
*/
public String getResult() {
return result;
}
/**
* <p>Get the output as the formatted result.</p>
* <p>The formatted result is created with the boolean options.</p>
* <p>The options can be set by accessing them as an instance variable.</p>
* <table border="1">
* <tr><th>Option name</th><th>Description</th></tr>
* <tr><td>removeNamespaceReferences</td><td><p>All namespace references will be removed.</p>
* <p>The xmlns variables as well as the 'ns:' will be replaced by an empty string.</p></td></tr>
* <tr><td>removeWhitespaceBetweenTags</td><td><p>All whitespaces between the tags are removed.</p>
* <p>Essentially this means that the string will be returned as one line.
* This is beneficial for predictable assertions.</p></td></tr>
* </table>
*
* @return java.lang.String
*/
public String getFormattedResult() {
return format(result);
}
/**
* <p>Compile the given XPath and put the result in the class variable.</p>
* <p>Get the result with {@link #getResult()}</p>
*
* @param xpath
* @return
* @throws SaxonApiException
*/
public XmlSupport compileXPath(String xpath) throws SaxonApiException {
query = xpath;
saxResult = processor.newXPathCompiler().evaluate(query, saxXml);
result = saxResult.toString();
return this;
}
/**
* <p>Compile the given XQuery and put the result in the class variable.</p>
*
* @param xquery
* @return
* @throws SaxonApiException
*/
public XmlSupport compileXQuery(String xquery) throws SaxonApiException {
query = xquery;
XQueryEvaluator xqe = processor
.newXQueryCompiler()
.compile(query)
.load();
xqe.setContextItem(saxXml);
saxResult = xqe.evaluate();
result = saxResult.toString();
return this;
}
/**
* <p>Format the result string as specified by the options booleans.</p>
*
* @param xml - String
* @return String
*/
private String format(String xml) {
String formattedResult = result;
if(removeNamespaceReferences) {
formattedResult = formattedResult
.replaceAll(XMLNS_DEFINITION_REGEX, "")
.replaceAll(IN_MESSAGE_NAMESPACE_REGEX, "");
}
if(removeWhitespaceBetweenTags) {
formattedResult = formattedResult.replaceAll(BETWEEN_TAG_WHITESPACE_REGEX, "");
}
return formattedResult;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment