Package xbird.xquery.expr.constructor

Source Code of xbird.xquery.expr.constructor.ElementConstructor

/*
* @(#)$Id: ElementConstructor.java 3619 2008-03-26 07:23:03Z yui $
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.xquery.expr.constructor;

import java.util.*;

import xbird.util.xml.NamespaceBinder;
import xbird.xquery.TypeError;
import xbird.xquery.XQueryException;
import xbird.xquery.dm.XQEventReceiver;
import xbird.xquery.dm.instance.XQueryDataModel;
import xbird.xquery.dm.value.Item;
import xbird.xquery.dm.value.Sequence;
import xbird.xquery.dm.value.node.*;
import xbird.xquery.dm.value.sequence.CloneNodesSequence;
import xbird.xquery.dm.value.sequence.ValueSequence;
import xbird.xquery.expr.XQExpression;
import xbird.xquery.meta.*;
import xbird.xquery.misc.QNameTable.QualifiedName;
import xbird.xquery.parser.XQueryParserVisitor;
import xbird.xquery.type.node.ElementTest;

/**
*
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
* @link http://www.w3.org/TR/xquery/#doc-xquery-CompElemConstructor
* @link http://www.w3.org/TR/xquery-semantics/#sec_comp_elem_constructor
* @link http://www.w3.org/TR/xquery/#id-attributes
* @link http://www.w3.org/TR/xquery/#id-content
*/
public final class ElementConstructor extends NameExprConstructor {
    private static final long serialVersionUID = 1533995309945289717L;

    private final QualifiedName name; // avoid null
    private int _attslen;
    private final List<AttributeConstructorBase> attributes;
    private final ArrayList<XQExpression> contents = new ArrayList<XQExpression>(8); // intentional use of ArrayList

    public ElementConstructor(QualifiedName name) {
        this(name, new ArrayList<AttributeConstructorBase>(4));
    }

    public ElementConstructor(QualifiedName name, List<AttributeConstructorBase> atts) {
        this.name = name;
        this._attslen = atts.size();
        this.attributes = atts;
        this._type = name == null ? ElementTest.ANY_ELEMENT : new ElementTest(name);
    }

    public ElementConstructor(XQExpression nameExpr) {
        this(null, Collections.<AttributeConstructorBase> emptyList());
        this._nameExpr = nameExpr;
    }

    public XQExpression visit(XQueryParserVisitor visitor, XQueryContext ctxt)
            throws XQueryException {
        return visitor.visit(this, ctxt);
    }

    //--------------------------------------------
    // getter / setter

    public QualifiedName getName() {
        return this.name;
    }

    public String getElemName() {
        StringBuilder buf = new StringBuilder(32);
        String prefix = name.getPrefix();
        if(prefix != null && prefix.length() > 0) {
            buf.append(prefix);
            buf.append(':');
        }
        buf.append(name.getLocalPart());
        return buf.toString();
    }

    public List<XQExpression> getContents() {
        return this.contents;
    }

    public List<AttributeConstructorBase> getAttributes() {
        return this.attributes;
    }

    public void addContent(XQExpression expr) throws TypeError {
        if(expr == null) {
            throw new IllegalArgumentException();
        }
        if(expr instanceof AttributeConstructorBase) {
            if(!contents.isEmpty()) {
                throw new TypeError("err:XQTY0024", "an attribute node following a node that is not an attribute node");
            }
            AttributeConstructorBase att = (AttributeConstructorBase) expr;
            if(att instanceof NamespaceConstructor) {
                attributes.add(0, att);
                ++_attslen;
            } else if(att instanceof AttributeConstructor) {
                attributes.add(att);
                ++_attslen;
            } else {
                throw new IllegalStateException("Illegal attribute class: "
                        + att.getClass().getName());
            }
        } else {
            contents.add(expr);
        }
    }

    @Deprecated
    public void addContent(TextContent expr) {
        assert (expr != null);
        if(expr == TextContent.TrimedText.INSTANCE) {
            return;
        }
        if(contents != null && !contents.isEmpty()) { // tiny optimization.
            int lastidx = contents.size() - 1;
            XQExpression lastEntry = contents.get(lastidx);
            if(lastEntry instanceof TextContent) {
                TextContent tc = (TextContent) lastEntry;
                if(tc.isCData() && expr.isCData()) {
                    tc.appendText(expr.getValue().toString());
                    return;
                }
            }
        }
        contents.add(expr);
    }

    //--------------------------------------------
    // static analysis / dynamic evaluation

    public XQExpression staticAnalysis(StaticContext statEnv) throws XQueryException {
        if(!_analyzed) {
            this._analyzed = true;
            if(name == null) {
                if(_nameExpr == null) {
                    reportError("err:XPTY0004", "name expression was null");
                }
                this._nameExpr = _nameExpr.staticAnalysis(statEnv);
            }
            for(AttributeConstructorBase att : attributes) {
                att.staticAnalysis(statEnv);
            }
            boolean stripSpace = statEnv.isStripBoundarySpace();
            int size = contents.size();
            if(size > 0) {
                int from = 0;
                {// trim head
                    XQExpression content = contents.get(0);
                    if(stripSpace && content instanceof TextContent) {
                        TextContent tc = (TextContent) content;
                        TextContent striped = stripBoundaryText(tc);
                        if(striped == null) {
                            contents.remove(0);
                            --size;
                        } else if(tc != striped) {
                            contents.set(0, striped);
                            ++from;
                        }
                    }
                }
                for(int i = from; i < size; i++) {
                    XQExpression c = contents.get(i);
                    if(stripSpace && i == (size - 1) && c instanceof TextContent) {// trim end
                        TextContent tc = (TextContent) c;
                        TextContent striped = stripBoundaryText(tc);
                        if(striped == null) {
                            contents.remove(i);
                        } else if(tc != striped) {
                            contents.set(i, striped);
                        }
                        break;
                    }
                    contents.set(i, c.staticAnalysis(statEnv));
                }
            }
        }
        return this;
    }

    private static TextContent stripBoundaryText(TextContent tc) {
        String c = tc.getValue().stringValue();
        String trimed = c.trim();
        int trimedLen = trimed.length();
        if(trimedLen == 0) {
            return null;
        }
        if(trimedLen != c.length()) {
            return new TextContent(trimed);
        }
        return tc;
    }

    public Sequence<? extends Item> eval(Sequence<? extends Item> contextSeq, DynamicContext dynEnv)
            throws XQueryException {
        QualifiedName instName = name;
        if(instName == null) {
            instName = processNameExpr(contextSeq, dynEnv);
        }
        DMElement dmelem = XQueryDataModel.createElement(instName);
        boolean hasNamespaceDecl = false;
        NamespaceBinder knownNamespaces = dynEnv.getStaticContext().getStaticalyKnownNamespaces();
        // process attribute/namespace
        for(AttributeConstructorBase att : attributes) {
            if(att instanceof NamespaceConstructor) {
                if(!hasNamespaceDecl) {
                    knownNamespaces.pushContext(); // TODO REVIEWME performance
                    hasNamespaceDecl = true;
                }
                NamespaceConstructor nc = ((NamespaceConstructor) att);
                DMNamespace dmns = nc.eval(contextSeq, dynEnv);
                dmelem.addNamespace(dmns);
                String nsprefix = nc.getPrefix();
                String nsuri = nc.getValue();
                knownNamespaces.declarePrefix(nsprefix, nsuri);
            } else if(att instanceof AttributeConstructor) {
                AttributeConstructor ac = (AttributeConstructor) att;
                DMAttribute dmatt = ac.eval(contextSeq, dynEnv);
                dmelem.addAttribute(dmatt);
            } else {
                throw new IllegalStateException("Expected to be NamespaceConstructor or AttributeConstructor instance, but was.. "
                        + att.getClass().getCanonicalName());
            }
        }
        // process children
        for(XQExpression content : contents) {
            Sequence childs = content.eval(contextSeq, dynEnv);
            if(childs != ValueSequence.EMPTY_SEQUENCE) {
                CloneNodesSequence clonedseq = new CloneNodesSequence(childs, dynEnv);           
                dmelem.addContents(clonedseq, dynEnv);
            }
        }
        if(hasNamespaceDecl) {
            knownNamespaces.popContext();
        }
        return dmelem;
    }

    @Override
    public void evalAsEvents(XQEventReceiver handler, Sequence<? extends Item> contextSeq, DynamicContext dynEnv)
            throws XQueryException {
        QualifiedName instName = name;
        if(instName == null) {
            instName = processNameExpr(contextSeq, dynEnv);
        }
        handler.evStartElement(instName);
        boolean hasNamespaceDecl = false;
        NamespaceBinder knownNamespaces = dynEnv.getStaticContext().getStaticalyKnownNamespaces();

        final int attlen = _attslen;
        for(int i = 0; i < attlen; i++) {
            AttributeConstructorBase att = attributes.get(i);
            if(att instanceof NamespaceConstructor) {
                if(!hasNamespaceDecl) {
                    knownNamespaces.pushContext(); // TODO REVIEWME performance
                    hasNamespaceDecl = true;
                }
                NamespaceConstructor nc = ((NamespaceConstructor) att);
                String nsprefix = nc.getPrefix();
                String nsuri = nc.getValue();
                knownNamespaces.declarePrefix(nsprefix, nsuri);
                handler.evNamespace(nsprefix, nsuri);
            } else {
                att.evalAsEvents(handler, contextSeq, dynEnv);
            }
        }
        final boolean old = handler.setBlankRequired(false);
        final int contentlen = contents.size();
        for(int i = 0; i < contentlen; i++) {
            XQExpression content = contents.get(i);
            content.evalAsEvents(handler, contextSeq, dynEnv);
            handler.setBlankRequired(true);
        }
        handler.setBlankRequired(old);

        if(hasNamespaceDecl) {
            knownNamespaces.popContext();
        }
        handler.evEndElement(instName);
    }

}
TOP

Related Classes of xbird.xquery.expr.constructor.ElementConstructor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.