blob: 834154079d5c1209218bfc570ab4d5abfa6b04c0 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* 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.
*/
package groovy.xml.streamingmarkupsupport;
import groovy.lang.Closure;
import groovy.lang.GroovyInterceptable;
import groovy.lang.GroovyObjectSupport;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class BaseMarkupBuilder extends Builder {
public BaseMarkupBuilder(final Map namespaceMethodMap) {
super(namespaceMethodMap);
}
public Object bind(final Closure root) {
return new Document(root, this.namespaceMethodMap);
}
private static class Document extends Built implements GroovyInterceptable {
private Object out;
private final Map pendingNamespaces = new HashMap();
private final Map namespaces = new HashMap();
private final Map specialProperties = new HashMap();
private String prefix = "";
{
namespaces.put("xml", "http://www.w3.org/XML/1998/namespace"); // built in namespace
namespaces.put("mkp", "http://www.codehaus.org/Groovy/markup/keywords"); // pseudo namespace for markup keywords
specialProperties.put("out", new OutputSink("out") {
public Object leftShift(final Object value) {
return leftShift("yield", value);
}
});
specialProperties.put("unescaped", new OutputSink("unescaped") {
public Object leftShift(final Object value) {
return leftShift("yieldUnescaped", value);
}
});
specialProperties.put("namespaces", new OutputSink("namespaces") {
public Object leftShift(final Object value) {
return leftShift("declareNamespace", value);
}
});
specialProperties.put("pi", new OutputSink("pi") {
public Object leftShift(final Object value) {
return leftShift("pi", value);
}
});
specialProperties.put("comment", new OutputSink("comment") {
public Object leftShift(final Object value) {
return leftShift("comment", value);
}
});
}
private abstract class OutputSink extends GroovyObjectSupport {
private final String name;
public OutputSink(final String name) {
this.name = name;
}
public Object invokeMethod(final String name, final Object args) {
Document.this.prefix = this.name;
return Document.this.invokeMethod(name, args);
}
public abstract Object leftShift(Object item);
protected Object leftShift(final String command, final Object value) {
Document.this.getProperty("mkp");
Document.this.invokeMethod(command, new Object[]{value});
return this;
}
}
public Document(final Closure root, final Map namespaceMethodMap) {
super(root, namespaceMethodMap);
}
/* (non-Javadoc)
* @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
*/
public Object invokeMethod(final String name, final Object args) {
final Object[] arguments = (Object[]) args;
Map attrs = Collections.EMPTY_MAP;
Object body = null;
//
// Sort the parameters out
//
for (int i = 0; i != arguments.length; i++) {
final Object arg = arguments[i];
if (arg instanceof Map) {
attrs = (Map) arg;
} else if (arg instanceof Closure) {
final Closure c = ((Closure) arg);
c.setDelegate(this);
body = c.asWritable();
} else {
body = arg;
}
}
//
// call the closure corresponding to the tag
//
final Object uri;
if (this.pendingNamespaces.containsKey(this.prefix)) {
uri = this.pendingNamespaces.get(this.prefix);
} else if (this.namespaces.containsKey(this.prefix)) {
uri = this.namespaces.get(this.prefix);
} else {
uri = ":";
}
final Object[] info = (Object[]) this.namespaceSpecificTags.get(uri);
final Map tagMap = (Map) info[2];
final Closure defaultTagClosure = (Closure) info[0];
final String prefix = this.prefix;
this.prefix = "";
if (tagMap.containsKey(name)) {
return ((Closure) tagMap.get(name)).call(new Object[]{this, this.pendingNamespaces, this.namespaces, this.namespaceSpecificTags, prefix, attrs, body, this.out});
} else {
return defaultTagClosure.call(new Object[]{name, this, this.pendingNamespaces, this.namespaces, this.namespaceSpecificTags, prefix, attrs, body, this.out});
}
}
/* (non-Javadoc)
* @see groovy.lang.GroovyObject#getProperty(java.lang.String)
*/
public Object getProperty(final String property) {
final Object special = this.specialProperties.get(property);
if (special == null) {
this.prefix = property;
return this;
} else {
return special;
}
}
/* (non-Javadoc)
* @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
*/
public void setProperty(String property, Object newValue) {
if ("trigger".equals(property)) {
this.out = newValue;
this.root.call(this);
} else {
super.setProperty(property, newValue);
}
}
}
}