package org.anodyneos.xpImpl.translater;
import org.anodyneos.commons.xml.sax.ElementProcessor;
import org.anodyneos.xpImpl.util.CodeWriter;
import org.anodyneos.xpImpl.util.Util;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Attribute element must have name and either expr attribute or text contents.
*
* This translater supports two modes:
*
* 1. No body mode if value attribute exists. Value of attribute is provided as an attribute of xp:attribute.
*
* 2. Optimized mode if body contains only text. Sets the attribute to the value of the content, or the value of the content
* after EL evaluations.
*
* 3. If body contains output elements and/or tags, processes the content using <code>ProcessorResultContent</code> to
* allow for runtime branching, etc. Sets attribute to runtime string result.
*
* TODO: provide proper context wrapping if necessary (review spec); generate new variables instead of reusing savedXPCH
* TODO: trim and crlf processing: support trim attribute, make sure result has
instead of CRLF (attrs not supposed to be on two lines in XML.)
*/
class ProcessorAttribute extends TranslaterProcessor {
public static final String A_NAME = "name";
public static final String A_NAMESPACE = "namespace";
public static final String A_VALUE = "value";
ProcessorResultContent processorResultContent;
private boolean valueAttributeMode = true;
private boolean optimizedMode = true;
private String savedXPOutVariable;
private StringBuffer sb;
private String codeName;
private String codeURI;
public ProcessorAttribute(TranslaterContext ctx) {
super(ctx);
}
public ElementProcessor getProcessorFor(String uri, String localName, String qName) throws SAXException {
if (valueAttributeMode) {
throw new SAXParseException("Element not allowed here: <" + qName + "> when @value is present on <xp:attribute>;", getContext().getLocator());
}
// new element is coming, so we cannot run in optimized mode.
if (optimizedMode) {
// switch to non-optimized mode
optimizedMode = false;
CodeWriter out = getTranslaterContext().getCodeWriter();
savedXPOutVariable = getTranslaterContext().getVariableForSavedXPOut();
out.printIndent().println( "org.anodyneos.xp.XpOutput " + savedXPOutVariable + " = xpOut;");
//out.printIndent().println( "savedXPCH = xpCH;");
out.printIndent().println( "xpOut = new org.anodyneos.xp.XpOutput(new org.anodyneos.xp.util.TextContentHandler());" );
out.printIndent().println( "xpCH = xpOut.getXpContentHandler();");
processorResultContent = new ProcessorResultContent(getTranslaterContext());
if (null != sb) {
processorResultContent.characters(sb.toString().toCharArray(), 0, sb.length());
sb = null;
}
}
return processorResultContent.getProcessorFor(uri, localName, qName);
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
CodeWriter out = getTranslaterContext().getCodeWriter();
String value = attributes.getValue(A_VALUE);
String attName = attributes.getValue(A_NAME);
String attURI = attributes.getValue(A_NAMESPACE);
/*if(null == attURI) {
attURI = "";
}*/
if(Util.hasEL(attName)) {
// EL expression may exist. Process all unescaped expressions, concatinate, etc...
codeName = Util.elExpressionCode(attName, "String");
} else {
codeName = Util.escapeStringQuotedEL(attName);
}
if (null == attURI) {
codeURI = "null";
} else if(Util.hasEL(attURI)) {
// EL expression may exist. Process all unescaped expressions, concatinate, etc...
codeURI = Util.elExpressionCode(attURI, "String");
} else {
codeURI = Util.escapeStringQuotedEL(attURI);
}
if (null == value) {
valueAttributeMode = false;
} else {
valueAttributeMode = true;
String codeValue;
if(Util.hasEL(value)) {
// EL expression may exist. Process all unescaped expressions, concatinate, etc...
codeValue = Util.elExpressionCode(value, "String");
} else {
codeValue = Util.escapeStringQuotedEL(value);
}
out.printIndent().println(
"xpCH.addAttribute("
+ codeURI
+ "," + codeName
+ "," + codeValue
+ ");"
);
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
if (valueAttributeMode) {
throw new SAXParseException("Text content not allowed here when @value is present on <xp:attribute>;", getContext().getLocator());
} else {
if (optimizedMode) {
if (null == sb) {
sb = new StringBuffer();
}
sb.append(ch, start, length);
} else {
processorResultContent.characters(ch, start, length);
}
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (valueAttributeMode) {
return;
}
CodeWriter out = getTranslaterContext().getCodeWriter();
String codeValue;
if (optimizedMode) {
if (sb != null) {
String value = sb.toString();
// Based on xsl tests, whitespace should be preserved (unless there is only whitespace)
if (value.trim().length() == 0) {
value = "";
}
if(Util.hasEL(value)) {
// EL expression may exist. Process all unescaped expressions, concatinate, etc...
codeValue = Util.elExpressionCode(value, "String");
} else {
codeValue = Util.escapeStringQuotedEL(value);
}
sb = null;
} else {
codeValue = Util.escapeStringQuoted("");
}
out.printIndent().println(
"xpCH.addAttribute("
+ codeURI
+ "," + codeName
+ "," + codeValue
+ ");"
);
} else {
// per xsl:attribute whitespace tests, don't trim
processorResultContent.flushCharacters();
out.printIndent().println(
savedXPOutVariable + ".addAttribute("
+ codeURI
+ "," + codeName
+ ", ((org.anodyneos.xp.util.TextContentHandler) xpCH.getWrappedContentHandler()).getText()"
+ ");"
);
out.printIndent().println( "xpOut = " + savedXPOutVariable + ";");
out.printIndent().println( "xpCH = xpOut.getXpContentHandler();");
out.printIndent().println( savedXPOutVariable + " = null;");
}
}
}