context.expressionStart(this);
context.pushInScopeNamespaces();
if (newDocumentContext)
{context.pushDocumentContext();}
try {
final MemTreeBuilder builder = context.getDocumentBuilder();
// declare namespaces
if(namespaceDecls != null) {
for(int i = 0; i < namespaceDecls.length; i++) {
//if ("".equals(namespaceDecls[i].getNamespaceURI())) {
// TODO: the specs are unclear here: should we throw XQST0085 or not?
// context.inScopeNamespaces.remove(namespaceDecls[i].getLocalName());
// if (context.inScopeNamespaces.remove(namespaceDecls[i].getLocalName()) == null)
// throw new XPathException(getAS TNode(), "XQST0085 : can not undefine '" + namespaceDecls[i] + "'");
//} else
context.declareInScopeNamespace(namespaceDecls[i].getLocalName(), namespaceDecls[i].getNamespaceURI());
}
}
// process attributes
final AttributesImpl attrs = new AttributesImpl();
if(attributes != null) {
AttributeConstructor constructor;
Sequence attrValues;
QName attrQName;
// first, search for xmlns attributes and declare in-scope namespaces
for (int i = 0; i < attributes.length; i++) {
constructor = attributes[i];
if(constructor.isNamespaceDeclaration()) {
final int p = constructor.getQName().indexOf(':');
if(p == Constants.STRING_NOT_FOUND)
{context.declareInScopeNamespace("", 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);
constructor = attributes[i];
attrValues = constructor.eval(contextSequence, contextItem);
attrQName = QName.parse(context, constructor.getQName(), "");
final String namespaceURI = attrQName.getNamespaceURI();
if (namespaceURI != null && !namespaceURI.isEmpty() && attrQName.getPrefix() == null) {
String prefix = context.getPrefixForURI(namespaceURI);
if (prefix != null) {
attrQName.setPrefix(prefix);
} else {
//generate prefix
for (final int n = 1; i < 100; i++) {
prefix = "eXnsp"+n;
if (context.getURIForPrefix(prefix) == null) {
attrQName.setPrefix(prefix);
break;
}
prefix = null;
}
if (prefix == null)
{throw new XPathException(this, "Prefix can't be generate.");}
}
}
if (attrs.getIndex(attrQName.getNamespaceURI(), attrQName.getLocalName()) != -1)
{throw new XPathException(this, ErrorCodes.XQST0040, "'" + attrQName.getLocalName() + "' is a duplicate attribute name");}
v = DynamicAttributeConstructor.normalize(this, attrQName, attrValues.getStringValue());
attrs.addAttribute(attrQName.getNamespaceURI(), attrQName.getLocalName(),
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 IllegalArgumentException 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;
}
//Use the default namespace if specified
/*
if (qn.getPrefix() == null && context.inScopeNamespaces.get("xmlns") != null) {
qn.setNamespaceURI((String)context.inScopeNamespaces.get("xmlns"));
}
*/
if (qn.getPrefix() == null && context.getInScopeNamespace("") != null) {
qn.setNamespaceURI(context.getInScopeNamespace(""));
}
}
//Not in the specs but... makes sense
if(!XMLChar.isValidName(qn.getLocalName()))
{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(int i = 0; i < namespaceDecls.length; i++) {
builder.namespaceNode(namespaceDecls[i]);
}
}
// do we need to add a namespace declaration for the current node?
if (qn.needsNamespaceDecl()) {
if (context.getInScopePrefix(qn.getNamespaceURI()) == null) {
String prefix = qn.getPrefix();
if (prefix == null || prefix.length() == 0)
{prefix = "";}
context.declareInScopeNamespace(prefix, qn.getNamespaceURI());
builder.namespaceNode(new QName(prefix, qn.getNamespaceURI(), "xmlns"));
}
} else if ((qn.getPrefix() == null || qn.getPrefix().length() == 0) &&
context.getInheritedNamespace("") != null) {
context.declareInScopeNamespace("", "");
builder.namespaceNode(new QName("", "", "xmlns"));
}
// 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();}