Permalink
Browse files

Fix #211 by adding an allow-text-results extension and turning text …

…output into encoded XML that's decoded by p:store
  • Loading branch information...
ndw committed May 22, 2015
1 parent 64d2152 commit 693224b6e876a94507d9211e9ae664c611e43f52
@@ -112,6 +112,7 @@
public String jsonFlavor = JSONtoXML.MARKLOGIC;
public boolean useXslt10 = false;
public boolean htmlSerializer = false;
+ public boolean allowTextResults = false;
public Vector<String> catalogs = new Vector<String> ();
public int piperackPort = 8088;
@@ -387,6 +388,7 @@ private void loadConfiguration() {
extensionValues = "true".equals(System.getProperty("com.xmlcalabash.general-values", ""+extensionValues));
xpointerOnText = "true".equals(System.getProperty("com.xmlcalabash.xpointer-on-text", ""+xpointerOnText));
transparentJSON = "true".equals(System.getProperty("com.xmlcalabash.transparent-json", ""+transparentJSON));
+ allowTextResults = "true".equals(System.getProperty("com.xmlcalabash.allow-text-results", ""+allowTextResults));
safeMode = "true".equals(System.getProperty("com.xmlcalabash.safe-mode", ""+safeMode));
jsonFlavor = System.getProperty("com.xmlcalabash.json-flavor", jsonFlavor);
useXslt10 = "true".equals(System.getProperty("com.xmlcalabash.use-xslt-10", ""+useXslt10));
@@ -721,6 +723,8 @@ private void parseExtension(XdmNode node) {
if (! JSONtoXML.knownFlavor(jsonFlavor)) {
throw new XProcException("Unrecognized JSON flavor: " + jsonFlavor);
}
+ } else if ("allow-text-results".equals(name)) {
+ allowTextResults = "true".equals(value);
} else if ("use-xslt-1.0".equals(name) || "use-xslt-10".equals(name)) {
useXslt10 = "true".equals(value);
} else if ("html-serializer".equals(name)) {
@@ -134,6 +134,7 @@
private URI baseURI = null;
private boolean allowGeneralExpressions = true;
private boolean allowXPointerOnText = true;
+ private boolean allowTextResults = true;
private boolean transparentJSON = false;
private String jsonFlavor = JSONtoXML.MARKLOGIC;
private boolean useXslt10 = false;
@@ -225,6 +226,7 @@ public XProcRuntime(XProcConfiguration config) {
allowGeneralExpressions = config.extensionValues;
allowXPointerOnText = config.xpointerOnText;
+ allowTextResults = config.allowTextResults;
transparentJSON = config.transparentJSON;
jsonFlavor = config.jsonFlavor;
useXslt10 = config.useXslt10;
@@ -459,6 +461,10 @@ public boolean getAllowXPointerOnText() {
return allowXPointerOnText;
}
+ public boolean getAllowTextResults() {
+ return allowTextResults;
+ }
+
public boolean transparentJSON() {
return transparentJSON;
}
@@ -661,6 +661,20 @@ public void setXPointerOnText(boolean xPointerOnText) {
}
}
+ /**
+ * Set whether non-XML (text) results can be returned from p:xslt and p:xquery steps,
+ * default is false.
+ *
+ * @param allowTextResults true if text results are allowed
+ */
+ public void setAllowTextResults(boolean allowTextResults) {
+ try {
+ userArgs.setAllowTextResults(allowTextResults);
+ } catch (Exception e) {
+ handleError(e);
+ }
+ }
+
/**
* Set whether to enable use of XSLT 1.0;
* optional, default is false.
@@ -126,6 +126,8 @@ public Sequence call(XPathContext xPathContext, Sequence[] sequences) throws XPa
value = runtime.jsonFlavor();
} else if ("general-values".equals(local)) {
value = runtime.getAllowGeneralExpressions() ? "true" : "false";
+ } else if ("allow-text-results".equals(local)) {
+ value = runtime.getAllowTextResults() ? "true" : "false";
} else if ("xpointer-on-text".equals(local)) {
value = runtime.getAllowXPointerOnText() ? "true" : "false";
} else if ("use-xslt-1.0".equals(local) || "use-xslt-10".equals(local)) {
@@ -55,7 +55,6 @@
public class Store extends DefaultStep {
private static final QName _href = new QName("href");
- private static final QName _encoding = new QName("encoding");
private static final QName _content_type = new QName("content-type");
private static final QName c_encoding = new QName("c", XProcConstants.NS_XPROC_STEP, "encoding");
private static final QName c_body = new QName("c", XProcConstants.NS_XPROC_STEP, "body");
@@ -116,8 +115,13 @@ public void run() throws SaxonApiException {
logger.trace(MessageFormatter.nodeMessage(hrefOpt.getNode(), "Storing to \"" + href + "\"."));
}
- String decode = step.getExtensionAttribute(cx_decode);
XdmNode root = S9apiUtils.getDocumentElement(doc);
+
+ String decode = step.getExtensionAttribute(cx_decode);
+ if (decode == null) {
+ decode = root.getAttributeValue(cx_decode);
+ }
+
String contentType = root.getAttributeValue(_content_type);
URI contentId;
if (("true".equals(decode) || "1".equals(decode) || method != CompressionMethod.NONE)
@@ -50,6 +50,7 @@
public class XQuery extends DefaultStep {
private static final QName _content_type = new QName("content-type");
+ private static final QName cx_decode = new QName("cx", XProcConstants.NS_CALABASH_EX, "decode");
private ReadablePipe source = null;
private Hashtable<QName,RuntimeValue> params = new Hashtable<QName,RuntimeValue> ();
@@ -140,10 +141,48 @@ public void run() throws SaxonApiException {
Iterator<XdmItem> iter = xqeval.iterator();
while (iter.hasNext()) {
XdmItem item = iter.next();
+ XdmNode node = null;
+
if (item.isAtomicValue()) {
- throw new XProcException(step.getNode(), "Not expecting atomic values back from XQuery!");
+ if (runtime.getAllowTextResults()) {
+ TreeWriter tree = new TreeWriter(runtime);
+ tree.startDocument(step.getNode().getBaseURI());
+ tree.addStartElement(XProcConstants.c_result);
+ tree.addAttribute(_content_type, "text/plain");
+ tree.addAttribute(cx_decode,"true");
+ tree.startContent();
+ tree.addText(item.getStringValue());
+ tree.addEndElement();
+ tree.endDocument();
+ node = tree.getResult();
+ } else {
+ throw new XProcException(step.getNode(), "p:xquery returned atomic value");
+ }
+ } else {
+ node = (XdmNode) item;
+
+ // If the document isn't well-formed XML, encode it as text
+ try {
+ S9apiUtils.assertDocument(node);
+ } catch (XProcException e) {
+ // If the document isn't well-formed XML, encode it as text
+ if (runtime.getAllowTextResults()) {
+ // Document is apparently not well-formed XML.
+ TreeWriter tree = new TreeWriter(runtime);
+ tree.startDocument(step.getNode().getBaseURI());
+ tree.addStartElement(XProcConstants.c_result);
+ tree.addAttribute(_content_type, "text/plain");
+ tree.addAttribute(cx_decode,"true");
+ tree.startContent();
+ tree.addText(node.toString());
+ tree.addEndElement();
+ tree.endDocument();
+ node = tree.getResult();
+ } else {
+ throw new XProcException(step.getStep(), "p:xquery returned non-XML result", e.getCause());
+ }
+ }
}
- XdmNode node = (XdmNode) item;
if (node.getNodeKind() != XdmNodeKind.DOCUMENT) {
// Make a document for this node...is this the right thing to do?
@@ -77,6 +77,8 @@
private static final QName _template_name = new QName("", "template-name");
private static final QName _output_base_uri = new QName("", "output-base-uri");
private static final QName _version = new QName("", "version");
+ private static final QName _content_type = new QName("content-type");
+ private static final QName cx_decode = new QName("cx", XProcConstants.NS_CALABASH_EX, "decode");
private ReadablePipe sourcePipe = null;
private ReadablePipe stylesheetPipe = null;
private WritablePipe resultPipe = null;
@@ -254,7 +256,29 @@ public void run() throws SaxonApiException {
String sysId = document.getBaseURI().toASCIIString();
xformed.getUnderlyingNode().setSystemId(sysId);
}
- resultPipe.write(xformed);
+
+ // If the document isn't well-formed XML, encode it as text
+ try {
+ S9apiUtils.assertDocument(xformed);
+ resultPipe.write(xformed);
+ } catch (XProcException e) {
+ // If the document isn't well-formed XML, encode it as text
+ if (runtime.getAllowTextResults()) {
+ // Document is apparently not well-formed XML.
+ TreeWriter tree = new TreeWriter(runtime);
+ tree.startDocument(xformed.getBaseURI());
+ tree.addStartElement(XProcConstants.c_result);
+ tree.addAttribute(_content_type, "text/plain");
+ tree.addAttribute(cx_decode,"true");
+ tree.startContent();
+ tree.addText(xformed.toString());
+ tree.addEndElement();
+ tree.endDocument();
+ resultPipe.write(tree.getResult());
+ } else {
+ throw new XProcException(step.getStep(), "p:xslt returned non-XML result", e.getCause());
+ }
+ }
}
}
@@ -333,7 +357,28 @@ public void close(Result result) throws TransformerException {
String href = result.getSystemId();
XdmDestination xdmResult = secondaryResults.get(href);
XdmNode doc = xdmResult.getXdmNode();
- secondaryPipe.write(doc);
+
+ try {
+ S9apiUtils.assertDocument(doc);
+ secondaryPipe.write(doc);
+ } catch (XProcException e) {
+ // If the document isn't well-formed XML, encode it as text
+ if (runtime.getAllowTextResults()) {
+ // Document is apparently not well-formed XML.
+ TreeWriter tree = new TreeWriter(runtime);
+ tree.startDocument(doc.getBaseURI());
+ tree.addStartElement(XProcConstants.c_result);
+ tree.addAttribute(_content_type, "text/plain");
+ tree.addAttribute(cx_decode,"true");
+ tree.startContent();
+ tree.addText(doc.toString());
+ tree.addEndElement();
+ tree.endDocument();
+ secondaryPipe.write(tree.getResult());
+ } else {
+ throw new XProcException(step.getStep(), "p:xslt returned non-XML secondary result", e.getCause());
+ }
+ }
}
}
@@ -149,6 +149,8 @@ public UserArgs parse(String[] args) {
userArgs.setExtensionValues(true);
} else if ("xpointer-on-text".equals(ext)) {
userArgs.setAllowXPointerOnText(true);
+ } else if ("allow-text-results".equals(ext)) {
+ userArgs.setAllowTextResults(true);
} else if ("use-xslt-1.0".equals(ext) || "use-xslt-10".equals(ext)) {
userArgs.setUseXslt10(true);
} else if ("html-serializer".equals(ext)) {
@@ -85,6 +85,7 @@
protected StepArgs lastStep = null;
protected boolean extensionValues = false;
protected boolean allowXPointerOnText = false;
+ protected boolean allowTextResults = false;
protected boolean useXslt10 = false;
protected boolean htmlSerializer = false;
protected boolean transparentJSON = false;
@@ -404,6 +405,10 @@ public void setAllowXPointerOnText(boolean allowXPointerOnText) {
this.allowXPointerOnText = allowXPointerOnText;
}
+ public void setAllowTextResults(boolean allowTextResults) {
+ this.allowTextResults = allowTextResults;
+ }
+
public void setUseXslt10(boolean useXslt10) {
this.useXslt10 = useXslt10;
}
@@ -556,6 +561,7 @@ public XProcConfiguration createConfiguration() throws SaxonApiException {
if ((jsonFlavor != null) && !knownFlavor(jsonFlavor)) {
config.jsonFlavor = jsonFlavor;
}
+ config.allowTextResults |= allowTextResults;
config.useXslt10 |= useXslt10;
config.htmlSerializer |= htmlSerializer;

0 comments on commit 693224b

Please sign in to comment.