
net.jangaroo.extxml.xml.ExmlToJsonHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ext-xml Show documentation
Show all versions of ext-xml Show documentation
Allows a declarative description of UI components
The newest version!
/*
* Copyright (c) 2009, CoreMedia AG, Hamburg. All rights reserved.
*/
package net.jangaroo.extxml.xml;
import net.jangaroo.extxml.json.Json;
import net.jangaroo.extxml.json.JsonArray;
import net.jangaroo.extxml.json.JsonObject;
import net.jangaroo.extxml.file.ExmlComponentSrcFileScanner;
import net.jangaroo.extxml.model.ComponentSuite;
import net.jangaroo.extxml.model.ComponentClass;
import net.jangaroo.utils.log.Log;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Stack;
/**
* Generates an internal representation for the component XML
*/
public final class ExmlToJsonHandler extends CharacterRecordingHandler {
private Locator locator;
private Json result;
private String resultXtype;
private final ComponentSuite componentSuite;
private Set imports = new LinkedHashSet();
private static String numberPattern = "-?([0-9]+\\.[0-9]*)|(\\.[0-9]+)|([0-9]+)([eE][+-]?[0-9]+)?";
private NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
private Stack objects = new Stack();
private Stack attributes = new Stack();
private boolean expectObjects = true;
public ExmlToJsonHandler(ComponentSuite componentSuite) {
this.componentSuite = componentSuite;
}
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void endDocument() throws SAXException {
if (!objects.empty()) {
throw new SAXParseException("Json object stack not empty at the end of the document.", locator);
}
if (!attributes.empty()) {
throw new SAXParseException("Attribute stack not empty at the end of the document.", locator);
}
if (!expectObjects) {
throw new SAXParseException("The parser is in the wrong state at the end of the document.", locator);
}
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (ExmlComponentSrcFileScanner.EXML_NAMESPACE_URI.equals(uri)) {
if ("import".equals(localName)) {
imports.add(atts.getValue("class"));
} else if ("object".equals(localName)) {
//handle json elements differently: either as a anonymous element with attributes or
//json as text node of the element.
if (expectObjects) {
if (atts.getLength() == 0) {
//start recording characters of the JSON string:
startRecordingCharacters();
} else {
addElementToJsonObject(createJsonObject(atts));
}
}
}
} else {
JsonObject jsonObject = createJsonObject(atts);
Json parentJson = objects.empty() ? null : objects.peek();
if (expectObjects) {
jsonObject.setTypePropertyName("xtype");
if (!attributes.isEmpty()) {
String attribute = attributes.peek();
if (attribute.equals("plugins")) {
jsonObject.setTypePropertyName("ptype");
} else if (attribute.equals("layout")) {
jsonObject.setTypePropertyName("type");
} else if (attribute.equals("baseAction")) {
jsonObject.setTypePropertyName("atype");
}
}
//find component class for namespace + localName:
ComponentClass compClazz = componentSuite.getComponentClassByNamespaceAndLocalName(uri, localName);
if (compClazz != null) {
imports.add(compClazz.getFullClassName());
jsonObject.setType(compClazz.getXtype());
} else {
Log.e(String.format("No component class for element name '%s' found in component suite '%s'!", localName, uri), locator.getLineNumber(), locator.getColumnNumber());
jsonObject.setType(localName);
}
addElementToJsonObject(jsonObject);
addObjectToStack(jsonObject);
} else {
assert parentJson != null;
addAttributeToStack(localName);
if (!jsonObject.isEmpty()) {
parentJson.set(localName, jsonObject);
addObjectToStack(jsonObject);
}
}
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (ExmlComponentSrcFileScanner.EXML_NAMESPACE_URI.equals(uri)) {
if ("object".equals(localName)) {
String characters = popRecordedCharacters();
if (characters != null) {
addElementToJsonObject("{" + characters.trim() + "}");
}
}
} else {
if (expectObjects) {
String attr = attributes.pop();
assert localName.equals(attr);
expectObjects = false;
} else {
net.jangaroo.extxml.json.Json json = removeObjectFromStack();
if (!(json instanceof JsonObject && ((JsonObject)json).getTypePropertyName() != null)) {
removeAttributeFromStack();
}
//if the the last object has been removed,
//store the result
if (objects.empty()) {
result = json;
resultXtype = (String)((JsonObject) result).remove("xtype");
}
}
}
}
private JsonObject createJsonObject(Attributes atts) {
JsonObject newJsonObject = new JsonObject();
for (int i = 0; i < atts.getLength(); i++) {
String attsValue = atts.getValue(i);
Object typedValue;
if ("true".equals(attsValue) || "false".equals(attsValue)) {
typedValue = Boolean.parseBoolean(attsValue);
} else if (attsValue.matches(numberPattern)) {
try {
typedValue = nf.parse(attsValue);
} catch (ParseException e) {
//well seems to be not a number...
typedValue = attsValue;
}
} else {
typedValue = attsValue;
}
newJsonObject.set(atts.getLocalName(i), typedValue);
}
return newJsonObject;
}
/**
* adds the element to the current json object, if it is an array knows how to handle it...
*
* @param element the element to add.
*/
private void addElementToJsonObject(Object element) {
Json parentJson = objects.empty() ? null : objects.peek();
if (parentJson != null) {
assert !attributes.empty();
String attr = attributes.peek();
Object obj = parentJson.get(attr);
if (obj == null) {
parentJson.set(attr, element);
} else if (!(obj instanceof JsonArray)) {
JsonArray array = new JsonArray();
array.push(obj);
array.push(element);
parentJson.set(attr, array);
} else {
((JsonArray) obj).push(element);
}
}
}
/**
* Adds the Json to the stack and
* indicates that no other json object is expected by the parser
*
* @param jsonObject the json to add to the stack
*/
private void addObjectToStack(Json jsonObject) {
objects.push(jsonObject);
expectObjects = false;
}
/**
* Adds the Attribute to the stack and
* indicates that now only json objects are expected by the parser
*
* @param attribute the name of the attribute
*/
private void addAttributeToStack(String attribute) {
attributes.push(attribute);
expectObjects = true;
}
/**
* Removes the last json object from stack and indicates that other json objects
* are expected by the parser
*
* @return the last json object from the stack
*/
private Json removeObjectFromStack() {
expectObjects = true;
return objects.pop();
}
/**
* Remove the last attribute from the attribute stack and indicate that attributes are
* expected by the parser
*/
private void removeAttributeFromStack() {
attributes.pop();
expectObjects = false;
}
public List getImports() {
return new ArrayList(imports);
}
public Json getJson() {
return result;
}
public String getXtype() {
return resultXtype;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy