use of org.exist.dom.memtree.MemTreeBuilder in project exist by eXist-db.
the class ElementConstructor method eval.
@Override
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
context.expressionStart(this);
context.pushInScopeNamespaces();
if (newDocumentContext) {
context.pushDocumentContext();
}
try {
final MemTreeBuilder builder = context.getDocumentBuilder();
// declare namespaces
if (namespaceDecls != null) {
for (QName namespaceDecl : namespaceDecls) {
// if ("".equals(namespaceDecls[i].getNamespaceURI())) {
// TODO: the specs are unclear here: should we throw XQST0085 or not?
// context.inScopeNamespaces.remove(namespaceDecls[i].getLocalPart());
// if (context.inScopeNamespaces.remove(namespaceDecls[i].getLocalPart()) == null)
// throw new XPathException(getAS TNode(), "XQST0085 : can not undefine '" + namespaceDecls[i] + "'");
// } else
context.declareInScopeNamespace(namespaceDecl.getLocalPart(), namespaceDecl.getNamespaceURI());
}
}
// process attributes
final AttributesImpl attrs = new AttributesImpl();
if (attributes != null) {
// first, search for xmlns attributes and declare in-scope namespaces
for (final AttributeConstructor constructor : attributes) {
if (constructor.isNamespaceDeclaration()) {
final int p = constructor.getQName().indexOf(':');
if (p == Constants.STRING_NOT_FOUND) {
context.declareInScopeNamespace(XMLConstants.DEFAULT_NS_PREFIX, constructor.getLiteralValue());
} else {
final String prefix = constructor.getQName().substring(p + 1);
context.declareInScopeNamespace(prefix, constructor.getLiteralValue());
}
}
}
String v = null;
// process the remaining attributes
for (int i = 0; i < attributes.length; i++) {
context.proceed(this, builder);
final AttributeConstructor constructor = attributes[i];
final Sequence attrValues = constructor.eval(contextSequence, contextItem);
QName attrQName;
try {
attrQName = QName.parse(context, constructor.getQName(), XMLConstants.NULL_NS_URI);
} catch (final QName.IllegalQNameException e) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + constructor.getQName() + "' is not a valid attribute name");
}
final String namespaceURI = attrQName.getNamespaceURI();
if (namespaceURI != null && !namespaceURI.isEmpty() && attrQName.getPrefix() == null) {
String prefix = context.getPrefixForURI(namespaceURI);
if (prefix != null) {
attrQName = new QName(attrQName.getLocalPart(), attrQName.getNamespaceURI(), prefix);
} else {
// generate prefix
for (final int n = 1; i < 100; i++) {
prefix = "eXnsp" + n;
if (context.getURIForPrefix(prefix) == null) {
attrQName = new QName(attrQName.getLocalPart(), attrQName.getNamespaceURI(), prefix);
break;
}
prefix = null;
}
if (prefix == null) {
throw new XPathException(this, "Prefix can't be generated.");
}
}
}
if (attrs.getIndex(attrQName.getNamespaceURI(), attrQName.getLocalPart()) != -1) {
throw new XPathException(this, ErrorCodes.XQST0040, "'" + attrQName.getLocalPart() + "' is a duplicate attribute name");
}
v = DynamicAttributeConstructor.normalize(this, attrQName, attrValues.getStringValue());
attrs.addAttribute(attrQName.getNamespaceURI(), attrQName.getLocalPart(), attrQName.getStringValue(), "CDATA", v);
}
}
context.proceed(this, builder);
// create the element
final Sequence qnameSeq = qnameExpr.eval(contextSequence, contextItem);
if (!qnameSeq.hasOne()) {
throw new XPathException(this, ErrorCodes.XPTY0004, "Type error: the node name should evaluate to a single item");
}
final Item qnitem = qnameSeq.itemAt(0);
QName qn;
if (qnitem instanceof QNameValue) {
qn = ((QNameValue) qnitem).getQName();
} else {
// Do we have the same result than Atomize there ? -pb
try {
qn = QName.parse(context, qnitem.getStringValue());
} catch (final QName.IllegalQNameException e) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + qnitem.getStringValue() + "' is not a valid element name");
} catch (final XPathException e) {
e.setLocation(getLine(), getColumn(), getSource());
throw e;
}
/*
if (qn.getPrefix() == null && context.inScopeNamespaces.get("xmlns") != null) {
qn.setNamespaceURI((String)context.inScopeNamespaces.get("xmlns"));
}
*/
if (qn.getPrefix() == null && context.getInScopeNamespace(XMLConstants.DEFAULT_NS_PREFIX) != null) {
qn = new QName(qn.getLocalPart(), context.getInScopeNamespace(XMLConstants.DEFAULT_NS_PREFIX), qn.getPrefix());
}
}
// Not in the specs but... makes sense
if (!XMLNames.isName(qn.getLocalPart())) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + qnitem.getStringValue() + "' is not a valid element name");
}
// add namespace declaration nodes
final int nodeNr = builder.startElement(qn, attrs);
if (namespaceDecls != null) {
for (QName namespaceDecl : namespaceDecls) {
builder.namespaceNode(namespaceDecl);
}
}
// do we need to add a namespace declaration for the current node?
if (qn.hasNamespace()) {
if (context.getInScopePrefix(qn.getNamespaceURI()) == null) {
String prefix = qn.getPrefix();
if (prefix == null) {
prefix = XMLConstants.DEFAULT_NS_PREFIX;
}
context.declareInScopeNamespace(prefix, qn.getNamespaceURI());
builder.namespaceNode(new QName(prefix, qn.getNamespaceURI(), XMLConstants.XMLNS_ATTRIBUTE));
}
} else if ((qn.getPrefix() == null || qn.getPrefix().length() == 0) && context.getInheritedNamespace(XMLConstants.DEFAULT_NS_PREFIX) != null) {
context.declareInScopeNamespace(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI);
builder.namespaceNode(new QName("", XMLConstants.NULL_NS_URI, XMLConstants.XMLNS_ATTRIBUTE));
} else if (qn.getPrefix() == null || qn.getPrefix().length() == 0) {
context.declareInScopeNamespace(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI);
}
// process element contents
if (content != null) {
content.eval(contextSequence, contextItem);
}
builder.endElement();
final NodeImpl node = builder.getDocument().getNode(nodeNr);
return node;
} finally {
context.popInScopeNamespaces();
if (newDocumentContext) {
context.popDocumentContext();
}
context.expressionEnd(this);
}
}
use of org.exist.dom.memtree.MemTreeBuilder in project exist by eXist-db.
the class EnclosedExpr method eval.
/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#eval(org.exist.xquery.StaticContext,
* org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
// evaluate the expression
Sequence result;
context.enterEnclosedExpr();
try {
context.pushDocumentContext();
try {
result = super.eval(contextSequence, null);
} finally {
context.popDocumentContext();
}
// create the output
final MemTreeBuilder builder = context.getDocumentBuilder();
final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(builder);
receiver.setCheckNS(true);
try {
// flatten all arrays in the input sequence
result = ArrayType.flatten(result);
final SequenceIterator i = result.iterate();
Item next = i.nextItem();
StringBuilder buf = null;
boolean allowAttribs = true;
while (next != null) {
context.proceed(this, builder);
if (Type.subTypeOf(next.getType(), Type.FUNCTION_REFERENCE)) {
throw new XPathException(this, ErrorCodes.XQTY0105, "Enclosed expression contains function item");
// if item is an atomic value, collect the string values of all
// following atomic values and separate them by a space.
} else if (Type.subTypeOf(next.getType(), Type.ATOMIC)) {
if (buf == null) {
buf = new StringBuilder();
} else if (buf.length() > 0) {
buf.append(' ');
}
buf.append(next.getStringValue());
allowAttribs = false;
next = i.nextItem();
// If the item is a node, flush any collected character data and
// copy the node to the target doc.
} else if (Type.subTypeOf(next.getType(), Type.NODE)) {
// such a text node will be deleted or merged with another text node.
if (next instanceof TextImpl && ((TextImpl) next).getStringValue().isEmpty()) {
next = i.nextItem();
continue;
}
if (buf != null && buf.length() > 0) {
receiver.characters(buf);
buf.setLength(0);
}
if (next.getType() == Type.ATTRIBUTE && !allowAttribs) {
throw new XPathException(this, ErrorCodes.XQTY0024, "An attribute may not appear after another child node.");
}
try {
receiver.setCheckNS(false);
next.copyTo(context.getBroker(), receiver);
receiver.setCheckNS(true);
} catch (DOMException e) {
if (e.code == DOMException.NAMESPACE_ERR) {
throw new XPathException(this, ErrorCodes.XQDY0102, e.getMessage());
} else {
throw new XPathException(this, e.getMessage(), e);
}
}
allowAttribs = next.getType() == Type.ATTRIBUTE || next.getType() == Type.NAMESPACE;
next = i.nextItem();
}
}
// flush remaining character data
if (buf != null && buf.length() > 0) {
receiver.characters(buf);
}
} catch (final SAXException e) {
LOG.warn("SAXException during serialization: {}", e.getMessage(), e);
throw new XPathException(this, e);
}
} finally {
context.exitEnclosedExpr();
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.dom.memtree.MemTreeBuilder in project exist by eXist-db.
the class DocumentConstructor method eval.
/* (non-Javadoc)
* @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
context.pushDocumentContext();
final Sequence contentSeq = content.eval(contextSequence, contextItem);
context.popDocumentContext();
context.pushDocumentContext();
final MemTreeBuilder builder = context.getDocumentBuilder(true);
final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(builder);
try {
if (!contentSeq.isEmpty()) {
StringBuilder buf = null;
final SequenceIterator i = contentSeq.iterate();
Item next = i.nextItem();
while (next != null) {
context.proceed(this, builder);
if (next.getType() == Type.ATTRIBUTE || next.getType() == Type.NAMESPACE) {
throw new XPathException(this, "Found a node of type " + Type.getTypeName(next.getType()) + " inside a document constructor");
}
// following atomic values and seperate them by a space.
if (Type.subTypeOf(next.getType(), Type.ATOMIC)) {
if (buf == null) {
buf = new StringBuilder();
} else if (buf.length() > 0) {
buf.append(' ');
}
buf.append(next.getStringValue());
next = i.nextItem();
// if item is a node, flush any collected character data and
// copy the node to the target doc.
} else if (next.getType() == Type.DOCUMENT) {
if (buf != null && buf.length() > 0) {
receiver.characters(buf);
buf.setLength(0);
}
next.copyTo(context.getBroker(), receiver);
next = i.nextItem();
} else if (Type.subTypeOf(next.getType(), Type.NODE)) {
if (buf != null && buf.length() > 0) {
receiver.characters(buf);
buf.setLength(0);
}
next.copyTo(context.getBroker(), receiver);
next = i.nextItem();
}
}
// flush remaining character data
if (buf != null && buf.length() > 0) {
receiver.characters(buf);
buf.setLength(0);
}
}
} catch (final SAXException e) {
throw new XPathException(this, "Encountered SAX exception while processing document constructor: " + ExpressionDumper.dump(this));
}
context.popDocumentContext();
final NodeImpl node = builder.getDocument();
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", node);
}
return node;
}
use of org.exist.dom.memtree.MemTreeBuilder in project exist by eXist-db.
the class CDATAConstructor method eval.
@Override
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (newDocumentContext) {
context.pushDocumentContext();
}
try {
final MemTreeBuilder builder = context.getDocumentBuilder();
final NodeImpl node = builder.getDocument().getNode(builder.cdataSection(cdata));
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", node);
}
return node;
} finally {
if (newDocumentContext) {
context.popDocumentContext();
}
}
}
use of org.exist.dom.memtree.MemTreeBuilder in project exist by eXist-db.
the class ExecuteFunctionTest method testEmptyParameters.
@Test
public void testEmptyParameters() throws SQLException, XPathException {
// mocks a simple SQL prepared statement with one parameter
// is filled with an empty xsl:param element
XQueryContext context = new XQueryContextStub();
ExecuteFunction execute = new ExecuteFunction(context, signatureByArity(ExecuteFunction.FS_EXECUTE, functionName, 3));
// this is what an empty xsl:param element of type varchar should use to fill prepared statement parameters
final String emptyStringValue = "";
final Integer emptyIntValue = null;
final String sql = "SELECT ? AS COL1, ? AS COL2";
// create mock objects
Connection connection = mock(Connection.class);
PreparedStatement preparedStatement = mock(PreparedStatement.class);
ResultSet rs = mock(ResultSet.class);
ResultSetMetaData rsmd = mock(ResultSetMetaData.class);
Object[] mocks = new Object[] { connection, preparedStatement, rs, rsmd };
// register mocked connection and prepared statement
final long connId = SQLModule.storeConnection(context, connection);
final long stmtId = SQLModule.storePreparedStatement(context, new PreparedStatementWithSQL(sql, preparedStatement));
// mock behavior
preparedStatement.setObject(1, emptyStringValue, Types.VARCHAR);
preparedStatement.setObject(2, emptyIntValue, Types.INTEGER);
expect(preparedStatement.getConnection()).andReturn(connection);
expect(preparedStatement.execute()).andReturn(true);
expect(preparedStatement.getResultSet()).andReturn(rs);
expect(preparedStatement.getUpdateCount()).andReturn(-1);
expect(rs.next()).andReturn(true).andReturn(false);
expect(rs.getRow()).andReturn(1);
expect(rs.getString(1)).andReturn(emptyStringValue);
expect(rs.wasNull()).andReturn(emptyStringValue == null);
expect(rs.getString(2)).andReturn(null);
expect(rs.wasNull()).andReturn(emptyIntValue == null);
expect(rs.getMetaData()).andStubReturn(rsmd);
expect(rsmd.getColumnCount()).andStubReturn(2);
expect(rsmd.getColumnLabel(1)).andStubReturn("COL1");
expect(rsmd.getColumnLabel(2)).andStubReturn("COL2");
expect(rsmd.getColumnTypeName(1)).andStubReturn("VARCHAR");
expect(rsmd.getColumnTypeName(2)).andStubReturn("INTEGER");
expect(rsmd.getColumnType(1)).andStubReturn(Types.VARCHAR);
expect(rsmd.getColumnType(2)).andStubReturn(Types.INTEGER);
rs.close();
replay(mocks);
// execute function
MemTreeBuilder paramBuilder = new MemTreeBuilder(context);
paramBuilder.startDocument();
paramBuilder.startElement(new QName("parameters", SQLModule.NAMESPACE_URI), null);
paramBuilder.startElement(new QName("param", SQLModule.NAMESPACE_URI), null);
paramBuilder.addAttribute(new QName("type", SQLModule.NAMESPACE_URI), "varchar");
paramBuilder.endElement();
paramBuilder.startElement(new QName("param", SQLModule.NAMESPACE_URI), null);
paramBuilder.addAttribute(new QName("type", SQLModule.NAMESPACE_URI), "integer");
paramBuilder.endElement();
paramBuilder.endElement();
paramBuilder.endDocument();
final ElementImpl sqlParams = (ElementImpl) paramBuilder.getDocument().getFirstChild();
execute.eval(new Sequence[] { new IntegerValue(connId), new IntegerValue(stmtId), sqlParams, new BooleanValue(false) }, Sequence.EMPTY_SEQUENCE);
// assert expectations
verify(preparedStatement);
}
Aggregations