Skip to content

Commit 122654d

Browse files
committed
[feature] Add support for setting XQuery external variables of type document(), comment(), processing-instruction(), and text() via the eXist-db REST API
1 parent bf73130 commit 122654d

File tree

2 files changed

+743
-48
lines changed

2 files changed

+743
-48
lines changed

exist-core/src/main/java/org/exist/xqj/Marshaller.java

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,13 @@
5252
import org.exist.xquery.NameTest;
5353
import org.exist.xquery.XPathException;
5454
import org.exist.xquery.value.*;
55+
import org.w3c.dom.Attr;
56+
import org.w3c.dom.Comment;
57+
import org.w3c.dom.Document;
5558
import org.w3c.dom.Element;
5659
import org.w3c.dom.Node;
60+
import org.w3c.dom.ProcessingInstruction;
61+
import org.w3c.dom.Text;
5762
import org.xml.sax.ContentHandler;
5863
import org.xml.sax.SAXException;
5964
import org.xml.sax.helpers.AttributesImpl;
@@ -242,7 +247,7 @@ public static Sequence demarshall(DBBroker broker, XMLStreamReader parser) throw
242247
return result;
243248
}
244249

245-
public static Sequence demarshall(NodeImpl node) throws XMLStreamException, XPathException {
250+
public static Sequence demarshall(final NodeImpl node) throws XMLStreamException, XPathException {
246251
final String ns = node.getNamespaceURI();
247252
if (ns == null || !NAMESPACE.equals(ns)) {
248253
throw new XMLStreamException("Root element is not in the correct namespace. Expected: " + NAMESPACE);
@@ -262,41 +267,84 @@ public static Sequence demarshall(NodeImpl node) throws XMLStreamException, XPat
262267
type = Type.getType(typeName);
263268
}
264269

265-
Item item;
270+
Node item = sxValue.getFirstChild();
266271
if (Type.subTypeOf(type, Type.NODE)) {
267-
item = (Item) sxValue.getFirstChild();
268-
if (type == Type.DOCUMENT) {
269-
final DocumentImpl n = (DocumentImpl) item;
270-
final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(n.getExpression());
271-
try {
272-
receiver.startDocument();
273-
n.copyTo(n, receiver);
274-
receiver.endDocument();
275-
} catch (final SAXException e) {
276-
throw new XPathException(item != null ? item.getExpression() : null, "Error while demarshalling node: " + e.getMessage(), e);
277-
}
278-
item = (Item) receiver.getDocument();
279-
}
280-
} else {
281-
final StringBuilder data = new StringBuilder();
282-
Node value = sxValue.getFirstChild();
283272

284-
if (value instanceof Element && type == Type.ITEM) {
285-
item = (NodeImpl) value;
273+
switch (type) {
274+
case Type.ELEMENT:
275+
if (item instanceof Document) {
276+
result.add((ElementImpl) ((DocumentImpl) item).getDocumentElement());
277+
} else if (!(item instanceof Element)) {
278+
throw new XMLStreamException("sx:value should only contain an Element if type is " + typeName);
279+
} else {
280+
result.add((ElementImpl) item);
281+
}
282+
break;
283+
284+
case Type.ATTRIBUTE:
285+
if (!(item instanceof Attr)) {
286+
throw new XMLStreamException("sx:value should only contain an Attribute if type is " + typeName);
287+
}
288+
result.add((AttrImpl) item);
289+
break;
290+
291+
case Type.COMMENT:
292+
if (!(item instanceof Comment)) {
293+
throw new XMLStreamException("sx:value should only contain a Comment node if type is " + typeName);
294+
}
295+
result.add((CommentImpl) item);
296+
break;
297+
298+
case Type.PROCESSING_INSTRUCTION:
299+
if (!(item instanceof ProcessingInstruction)) {
300+
throw new XMLStreamException("sx:value should only contain a Processing Instruction node if type is " + typeName);
301+
}
302+
result.add((ProcessingInstructionImpl) item);
303+
break;
304+
305+
case Type.TEXT:
306+
if (!(item instanceof Text)) {
307+
throw new XMLStreamException("sx:value should only contain a Text node if type is " + typeName);
308+
}
309+
result.add((TextImpl) item);
310+
break;
286311

287-
} else {
288-
while (value != null) {
289-
if (!(value.getNodeType() == Node.TEXT_NODE || value.getNodeType() == Node.CDATA_SECTION_NODE)) {
290-
throw new XMLStreamException("sx:value should only contain text if type is " + typeName);
312+
case Type.DOCUMENT:
313+
default:
314+
if (item instanceof Document || item instanceof Element) {
315+
final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(((NodeImpl) item).getExpression());
316+
try {
317+
receiver.startDocument();
318+
((NodeImpl) item).copyTo(null, receiver);
319+
receiver.endDocument();
320+
} catch (final SAXException e) {
321+
throw new XPathException(item != null ? ((NodeImpl) item).getExpression() : null, "Error while demarshalling node: " + e.getMessage(), e);
322+
}
323+
result.add((NodeImpl) receiver.getDocument());
324+
} else {
325+
throw new XMLStreamException("sx:value should only contain a Node if type is " + typeName);
291326
}
292-
data.append(value.getNodeValue());
293-
value = value.getNextSibling();
327+
break;
328+
}
329+
330+
} else if (type == Type.ITEM && !(item instanceof Text)) {
331+
// item() type requested and we have been given a node which is not a text() node
332+
result.add((NodeImpl) item);
333+
334+
} else {
335+
// specific non-node type or text()
336+
final StringBuilder data = new StringBuilder();
337+
while (item != null) {
338+
if (!(item.getNodeType() == Node.TEXT_NODE || item.getNodeType() == Node.CDATA_SECTION_NODE)) {
339+
throw new XMLStreamException("sx:value should only contain text if type is " + typeName);
294340
}
295-
item = new StringValue(data.toString()).convertTo(type);
341+
data.append(item.getNodeValue());
342+
item = item.getNextSibling();
296343
}
344+
result.add(new StringValue(data.toString()).convertTo(type));
297345
}
298-
result.add(item);
299346
}
347+
300348
return result;
301349
}
302350

0 commit comments

Comments
 (0)