package lux.xquery; import lux.xml.QName; import lux.xpath.AbstractExpression; import lux.xpath.ExpressionVisitor; import lux.xpath.LiteralExpression; import lux.xpath.Namespace; public class ElementConstructor extends AbstractExpression { private final QName name; public QName getName() { return name; } private final Namespace[] namespaces; private final AttributeConstructor[] attributes; /** * Make an element constructor - this models literal element constructors, not computed element * constructors. * @param qname the name of the element * @param namespaces this element's namespace declarations * @param content the content of the element * @param attributes the element's literal attributes - these AttributeConstructors * may only have LiteralExpressions for their names and values */ public ElementConstructor(QName qname, Namespace[] namespaces, AbstractExpression content, AttributeConstructor ... attributes) { super(Type.ELEMENT); this.name = qname; this.subs = new AbstractExpression[] { content }; this.namespaces = namespaces; this.attributes = attributes; } public ElementConstructor (QName qname, AbstractExpression content, AttributeConstructor ... attributes) { this (qname, null, content, attributes); } public ElementConstructor (QName qname, AttributeConstructor ... attributes) { super(Type.ELEMENT); this.name = qname; this.subs = new AbstractExpression[0]; this.namespaces = null; this.attributes = attributes; } @Override public AbstractExpression accept(ExpressionVisitor visitor) { acceptSubs(visitor); return visitor.visit(this); } @Override public void toString(StringBuilder buf) { buf.append ('<'); name.toString(buf); boolean hasNsDecl = namespaces != null && namespaces.length > 0; if (hasNsDecl) { buf.append (' '); appendNamespace(namespaces[0], buf); for (int i = 1; i < namespaces.length; i++) { buf.append (' '); appendNamespace(namespaces[i], buf); } } if (attributes != null && attributes.length > 0) { if (attributes[0] != null) { buf.append (' '); appendAttribute(attributes[0], buf); } for (int i = 1; i < attributes.length; i++) { if (attributes[i] != null) { buf.append (' '); appendAttribute(attributes[i], buf); } } } AbstractExpression content = getContent(); if (content == null) { buf.append ("/>"); } else { buf.append ('>'); switch (content.getType()) { case ELEMENT: content.toString(buf); break; case LITERAL: if (content != LiteralExpression.EMPTY) { LiteralExpression.escapeText(((LiteralExpression)content).getValue().toString(), buf); } break; case SEQUENCE: { boolean allElements = true; for (AbstractExpression kid : content.getSubs()) { if (kid.getType() != Type.ELEMENT) { allElements = false; break; } } if (allElements) { for (AbstractExpression kid : content.getSubs()) { kid.toString(buf); } break; } } default: buf.append ('{'); content.toString(buf); buf.append ('}'); } buf.append("</"); name.toString(buf); buf.append ('>'); } } private AbstractExpression getContent() { return subs.length > 0 ? subs[0] : null; } private void appendNamespace (Namespace ns, StringBuilder buf) { buf.append ("xmlns"); if (!ns.getPrefix().isEmpty()) { buf.append (':'); buf.append (ns.getPrefix()); } buf.append ("=\""); buf.append (ns.getNamespace()); buf.append ('"'); } private void appendAttribute (AttributeConstructor attr, StringBuilder buf) { buf.append (((LiteralExpression)attr.getName()).getValue().toString()); buf.append ('='); LiteralExpression.quoteString(((LiteralExpression)attr.getContent()).getValue().toString(), buf); } @Override public int getPrecedence () { return 0; } } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */