Skip to content

Commit

Permalink
[feature] Added support for XQuery 3.0 dynamic namespace constructor.
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfgangmm committed Aug 31, 2013
1 parent 61b4f2a commit 564b433
Show file tree
Hide file tree
Showing 11 changed files with 1,351 additions and 954 deletions.
3 changes: 3 additions & 0 deletions src/org/exist/memtree/DocumentImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,9 @@ private void copyStartNode(NodeImpl node, DocumentBuilderReceiver receiver, bool
final String data = new String(document.characters, document.alpha[nr], document.alphaLen[nr]);
receiver.processingInstruction(qn.getLocalName(), data);
break;
case NodeImpl.NAMESPACE_NODE:
receiver.addNamespaceNode(document.namespaceCode[nr]);
break;
case NodeImpl.REFERENCE_NODE:
if (expandRefs) {
DBBroker broker = null;
Expand Down
17 changes: 11 additions & 6 deletions src/org/exist/memtree/MemTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -446,13 +446,18 @@ public int namespaceNode( String prefix, String uri )
public int namespaceNode( QName qn )
{
final int lastNode = doc.getLastNode();
final QName elemQN = doc.nodeName[lastNode];
final String elemPrefix = ( elemQN.getPrefix() == null ) ? "" : elemQN.getPrefix();

if( elemPrefix.equals( qn.getLocalName() ) && ( elemQN.getNamespaceURI() != null ) && !elemQN.getNamespaceURI().equals( qn.getNamespaceURI() ) ) {
return( -1 );
boolean addNode = true;
if (doc.nodeName != null) {
final QName elemQN = doc.nodeName[lastNode];
if (elemQN != null) {
final String elemPrefix = ( elemQN.getPrefix() == null ) ? "" : elemQN.getPrefix();

if( elemPrefix.equals( qn.getLocalName() ) && ( elemQN.getNamespaceURI() != null ) && !elemQN.getNamespaceURI().equals( qn.getNamespaceURI() ) ) {
addNode = false;
}
}
}
return( doc.addNamespace( lastNode, qn ) );
return( addNode ? doc.addNamespace( lastNode, qn ) : -1 );
}


Expand Down
11 changes: 10 additions & 1 deletion src/org/exist/memtree/NamespaceNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public short getNodeType()
//XQuery doesn't support namespace nodes
//so, mapping as an attribute at *serialization tile* makes sense
//however, the Query parser should not accept them in constructors !
return( Node.ATTRIBUTE_NODE );
return( NodeImpl.NAMESPACE_NODE);
}


Expand Down Expand Up @@ -142,6 +142,15 @@ public void setValue( String value ) throws DOMException
{
}

@Override
public Node getFirstChild() {
return null;
}

@Override
public Node getLastChild() {
return null;
}

public String getNodeValue() throws DOMException
{
Expand Down
97 changes: 62 additions & 35 deletions src/org/exist/xquery/NamespaceConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,58 @@

import org.exist.memtree.DocumentImpl;
import org.exist.memtree.MemTreeBuilder;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.util.*;
import org.exist.xquery.util.Error;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;

import java.util.Iterator;


/**
* Implements a dynamic namespace constructor.
* XQuery 3.0 computed namespace constructor.
*
* @author wolf
*/
public class NamespaceConstructor extends NodeConstructor {

final private String prefix;
private Expression uri = null;
private Expression qnameExpr;
private Expression content = null;

/**
* @param context
*/
public NamespaceConstructor(XQueryContext context, String prefix) {
public NamespaceConstructor(XQueryContext context) {
super(context);
this.prefix = prefix;
}

public void setURIExpression(Expression uriExpr) {
this.uri = new Atomize(context, uriExpr);
public void setContentExpr(PathExpr path) {
path.setUseStaticContext(true);
final Expression expr = new DynamicCardinalityCheck(context, Cardinality.EXACTLY_ONE, path,
new Error(Error.FUNC_PARAM_CARDINALITY));
this.content = expr;
}

public void setNameExpr(Expression expr) {
expr = new Atomize(context, expr);
expr = new DynamicCardinalityCheck(context, Cardinality.ZERO_OR_ONE, expr,
new Error(Error.FUNC_PARAM_CARDINALITY));
this.qnameExpr = expr;
}

/* (non-Javadoc)
* @see org.exist.xquery.Expression#analyze(org.exist.xquery.Expression)
*/
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
contextInfo.setParent(this);
uri.analyze(contextInfo);
super.analyze(contextInfo);
final AnalyzeContextInfo newContextInfo = new AnalyzeContextInfo(contextInfo);
newContextInfo.setParent(this);
newContextInfo.addFlag(IN_NODE_CONSTRUCTOR);
qnameExpr.analyze(newContextInfo);
if (content != null) {
content.analyze(newContextInfo);
}
}

/* (non-Javadoc)
Expand All @@ -75,22 +93,14 @@ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathExc

final MemTreeBuilder builder = context.getDocumentBuilder();
context.proceed(this, builder);

final Sequence uriSeq = uri.eval(contextSequence, contextItem);
String value;
if(uriSeq.isEmpty())
{value = "";}
else {
final StringBuilder buf = new StringBuilder();
for(final SequenceIterator i = uriSeq.iterate(); i.hasNext(); ) {
context.proceed(this, builder);
final Item next = i.nextItem();
if(buf.length() > 0)
{buf.append(' ');}
buf.append(next.toString());
}
value = buf.toString();

final Sequence prefixSeq = qnameExpr.eval(contextSequence, contextItem);
String prefix = "";
if (!prefixSeq.isEmpty()) {
prefix = prefixSeq.getStringValue();
}
final Sequence uriSeq = content.eval(contextSequence, contextItem);
final String value = uriSeq.getStringValue();
context.declareInScopeNamespace(prefix, value);
final int nodeNr = builder.namespaceNode(prefix, value);
final Sequence result = ((DocumentImpl)builder.getDocument()).getNamespaceNode(nodeNr);
Expand All @@ -105,23 +115,40 @@ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathExc
* @see org.exist.xquery.Expression#dump(org.exist.xquery.util.ExpressionDumper)
*/
public void dump(ExpressionDumper dumper) {
dumper.display("namespace ").display(prefix);
dumper.display("namespace ");
//TODO : remove curly braces if Qname
dumper.display("{");
qnameExpr.dump(dumper);
dumper.display("} ");
dumper.display("{");
uri.dump(dumper);
dumper.display("}");
dumper.startIndent();
if(content != null) {
content.dump(dumper);
}
dumper.endIndent().nl();
dumper.display("} ");
}

public String toString() {
final StringBuilder result = new StringBuilder();
result.append("namespace ").append(prefix);
result.append("{");
result.append(uri.toString());
result.append("}");
return result.toString();
final StringBuilder result = new StringBuilder();
result.append("namespace ");
//TODO : remove curly braces if Qname
result.append("{");
result.append(qnameExpr.toString());
result.append("} ");
result.append("{");
if (content != null) {
result.append(content.toString());
}
result.append("} ");
return result.toString();
}

public void resetState(boolean postOptimization) {
super.resetState(postOptimization);
uri.resetState(postOptimization);
qnameExpr.resetState(postOptimization);
if(content != null) {
content.resetState(postOptimization);
}
}
}
37 changes: 15 additions & 22 deletions src/org/exist/xquery/parser/XQuery.g
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ stepExpr throws XPathException
( ( "text" | "node" | "element" | "attribute" | "comment" | "processing-instruction" | "document-node" ) LPAREN )
=> axisStep
|
( ( "element" | "attribute" | "text" | "document" | "processing-instruction" |
( ( "element" | "attribute" | "text" | "document" | "processing-instruction" | "namespace" |
"comment" | "ordered" | "unordered" | "map" ) LCURLY ) =>
postfixExpr
|
Expand Down Expand Up @@ -1128,7 +1128,7 @@ primaryExpr throws XPathException
{ String varName= null; }
:
( ( "element" | "attribute" | "text" | "document" | "processing-instruction" |
"comment" ) LCURLY ) =>
"comment" | "namespace" ) LCURLY ) =>
computedConstructor
|
( ( "element" | "attribute" | "processing-instruction" | "namespace" ) qName LCURLY ) => computedConstructor
Expand Down Expand Up @@ -1347,6 +1347,8 @@ computedConstructor throws XPathException
|
compTextConstructor
|
compNamespaceConstructor
|
compDocumentConstructor
|
compXmlPI
Expand All @@ -1360,27 +1362,13 @@ compElemConstructor throws XPathException
}
:
( "element" LCURLY ) =>
"element"! LCURLY! expr RCURLY! LCURLY! (compElemBody)? RCURLY!
"element"! LCURLY! expr RCURLY! LCURLY! (expr)? RCURLY!
{ #compElemConstructor = #(#[COMP_ELEM_CONSTRUCTOR], #compElemConstructor); }
|
"element"! qn=qName LCURLY! (e3:compElemBody)? RCURLY!
"element"! qn=qName LCURLY! (e3:expr)? RCURLY!
{ #compElemConstructor = #(#[COMP_ELEM_CONSTRUCTOR, qn], #[STRING_LITERAL, qn], #e3); }
;
compElemBody throws XPathException
:
(
( "namespace" ncnameOrKeyword LCURLY ) => localNamespaceDecl
|
exprSingle
)
( COMMA! (
( "namespace" ncnameOrKeyword LCURLY ) => localNamespaceDecl
|
exprSingle )
)*
;
compAttrConstructor throws XPathException
{
String qn;
Expand All @@ -1393,6 +1381,7 @@ compAttrConstructor throws XPathException
"attribute"! qn=qName e3:compConstructorValue
{ #compAttrConstructor = #(#[COMP_ATTR_CONSTRUCTOR, qn], #[STRING_LITERAL, qn], #e3); }
;
compConstructorValue throws XPathException
:
LCURLY^ ( e2:expr )? RCURLY!
Expand Down Expand Up @@ -1429,13 +1418,17 @@ compXmlComment throws XPathException
{ #compXmlComment = #(#[COMP_COMMENT_CONSTRUCTOR, "comment"], #e); }
;
localNamespaceDecl
compNamespaceConstructor throws XPathException
{
String nc = null;
String qn;
}
:
"namespace"! nc=ncnameOrKeyword LCURLY! l:STRING_LITERAL RCURLY!
{ #localNamespaceDecl = #(#[COMP_NS_CONSTRUCTOR, nc], #l); }
( "namespace" LCURLY ) =>
"namespace"! LCURLY! expr RCURLY! LCURLY! (expr)? RCURLY!
{ #compNamespaceConstructor = #(#[COMP_NS_CONSTRUCTOR], #compNamespaceConstructor); }
|
"namespace"! qn=qName LCURLY! (e3:expr)? RCURLY!
{ #compNamespaceConstructor = #(#[COMP_NS_CONSTRUCTOR, qn], #[STRING_LITERAL, qn], #e3); }
;
elementConstructor throws XPathException
Expand Down
Loading

0 comments on commit 564b433

Please sign in to comment.