package gr.ntua.ivml.mint.xml.transform;
import gr.ntua.ivml.mint.persistent.Transformation;
import gr.ntua.ivml.mint.xsd.XSDParser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import net.sf.json.*;
public class XSLTGenerator {
private static final Logger log = Logger.getLogger(XSDParser.class);
private String root = "";
private String match = "";
private StringBuffer variables = new StringBuffer();
private int variablesCount = 0;
private void resetVariables() {
variables = new StringBuffer();
variablesCount = 0;
}
private Stack<String> xpathPrefix = new Stack<String>();
private Map<String, String> importNamespaces;
/**
* Convenience function to retrieve XSL for a Transformation
* @param tr
* @return
*/
public static String getXsl( Transformation tr ) {
String mappings = tr.getMapping().getJsonString();
XSLTGenerator xslt = new XSLTGenerator();
xslt.setItemLevel(tr.getDataUpload().getItemXpath().getXpathWithPrefix(true));
xslt.setTemplateMatch(tr.getDataUpload().getItemXpath().getXpathWithPrefix(true));
xslt.setImportNamespaces(tr.getDataUpload().getRootXpath().getNamespaces(true));
String xsl = XMLFormatter.format(xslt.generateFromString(mappings));
return xsl;
}
public void setItemLevel(String root) {
this.root = root;
}
public String getItemLevel() {
return this.root;
}
public void setTemplateMatch(String match) {
this.match = match;
}
public String getTemplateMatch() {
return this.root;
/*
String[] tokens = this.root.split("/");
if(tokens.length == 0) {
return "/";
} else {
return "/" + tokens[tokens.length - 1];
}
*/
}
public String generateFromFile(String jsonFile) {
File targetDefinitionFile = new File(jsonFile);
if(targetDefinitionFile != null) {
StringBuffer targetDefinitionContents = new StringBuffer();
try {
BufferedReader reader = new BufferedReader(new FileReader(targetDefinitionFile));
if(reader != null) {
String line = null;
while((line = reader.readLine()) != null) {
targetDefinitionContents.append(line).append(System.getProperty("line.separator"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return generateFromString(targetDefinitionContents.toString());
}
return null;
}
public String generateFromString(String jsonstring) {
JSONObject mapping = (JSONObject) JSONSerializer.toJSON(jsonstring);
if(mapping != null) {
String xslt = generateFromJSONObject(mapping);
return xslt;
}
return null;
}
public String generateFromJSONObject(JSONObject mapping) {
resetVariables();
String xslt = "";
JSONArray groups = mapping.getJSONArray("groups");
xslt += "<?xml version=\"1.0\"?>";
String stylesheetNamespace = "";
StringBuilder sb = new StringBuilder();
JSONObject namespaces = new JSONObject();
if(mapping.has("namespaces")) {
namespaces = mapping.getJSONObject("namespaces");
for(Object o: namespaces.keySet()) {
String key = (String) o;
String value = namespaces.getString(key);
sb.append("xmlns:" + key + "=\"" + value + "\" ");
}
}
String excludeNamespaces = "";
if(this.importNamespaces != null) {
Iterator<String> i = this.importNamespaces.keySet().iterator();
while(i.hasNext()) {
String key = i.next();
String value = this.importNamespaces.get(key);
// stored differently than in json mapping -> key is value
if(!namespaces.has(value)) {
sb.append("xmlns:" + value + "=\"" + key + "\" ");
if(excludeNamespaces.length() > 0) {
excludeNamespaces += " ";
}
excludeNamespaces += value;
}
}
}
if(excludeNamespaces.length() > 0) {
excludeNamespaces = "exclude-result-prefixes=\"" + excludeNamespaces + "\"";
}
stylesheetNamespace = sb.toString();
xslt += "<xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " +
"xmlns:xalan=\"http://xml.apache.org/xalan\" " + stylesheetNamespace + " " + excludeNamespaces + ">";
// result += "<xsl:output omit-xml-declaration=\"yes\" />";
//default template - only proccess item level element and wrap it in defined wrap
String template = "";
template += "<xsl:template match=\"/\">";
if(mapping.has("wrap") && mapping.getJSONObject("wrap").has("element")) {
String wrap = ((mapping.getJSONObject("wrap")).has("prefix")?(mapping.getJSONObject("wrap")).getString("prefix") + ":":"") + mapping.getJSONObject("wrap").getString("element");
template += "<" + wrap + ">";
}
template += "<xsl:apply-templates select=\"" + this.getTemplateMatch() + "\"/>";
if(mapping.has("wrap") && mapping.getJSONObject("wrap").has("element")) {
String wrap = ((mapping.getJSONObject("wrap")).has("prefix")?(mapping.getJSONObject("wrap")).getString("prefix") + ":":"") + mapping.getJSONObject("wrap").getString("element");
template += "</" + wrap + ">";
}
template += "</xsl:template>";
// start item template
JSONObject jsonTemplate = mapping.getJSONObject("template");
template += "<xsl:template match=\"" + this.getTemplateMatch() + "\">";
template += this.generateTemplate(groups, jsonTemplate);
template += "</xsl:template>";
template += "</xsl:stylesheet>";
String result = xslt + variables.toString() + template;
return result;
}
private String generateTemplate(JSONArray groups, JSONObject template) {
String result = "";
if(template.has("name")) {
xpathPrefix.push(this.getTemplateMatch());
String name = template.getString("name");
String type = template.getString("type");
if(template.has("prefix")) {
name = template.getString("prefix") + ":" + name;
}
if(!type.equals("group")) {
JSONArray attributes = null;
JSONArray mappings = null;
if(template.has("mappings")) {
mappings = template.getJSONArray("mappings");
if(template.has("attributes")) {
attributes = template.getJSONArray("attributes");
}
if(mappings.size() > 0) {
if(mappings.size() == 1) {
result += generateWithMappings(name, attributes, mappings);
} else {
result += generateWithMappingsConcat(name, attributes, mappings);
}
}
}
if(template.has("children") && template.getJSONArray("children").size() > 0) {
result += "<" + name + ">";
if(template.has("attributes")) {
attributes = template.getJSONArray("attributes");
result += this.generateAttributes(attributes);
}
Iterator ci = template.getJSONArray("children").iterator();
while(ci.hasNext()) {
JSONObject child = (JSONObject) ci.next();
result += this.generateTemplate(groups, child);
}
result += "</" + name + ">";
}
} else {
Iterator gi = groups.iterator();
while(gi.hasNext()) {
JSONObject group = (JSONObject) gi.next();
String gname = group.getString("element");
if(template.getString("name").equals(gname)) {
String groupType = "element";
if(group.has("type")) {
groupType = group.getString("type");
}
if(groupType.equalsIgnoreCase("wrap")) {
JSONObject content = group.getJSONObject("contents");
if(content.has("children")) {
JSONArray children = content.getJSONArray("children");
log.debug("wrapping group" + gname + " count:" + children.size());
Iterator ci = children.iterator();
while(ci.hasNext()) {
JSONObject child = (JSONObject) ci.next();
result += generate(child);
}
}
} else {
JSONObject content = group.getJSONObject("contents");
result += generate(content);
}
}
}
}
xpathPrefix.pop();
}
return result;
}
private String generate(JSONObject item) {
String name = item.getString("name");
String prefix = null;
if(item.has("prefix")) {
name = item.getString("prefix") + ":" + name;
}
JSONArray attributes = null;
JSONArray children = null;
JSONArray mappings = null;
JSONObject condition = null;
JSONArray enumerations = null;
boolean single = false;
if(!descendantHasMappings(item)) {
return "";
}
if(item.has("attributes")) {
attributes = item.getJSONArray("attributes");
}
if(item.has("children")) {
children = item.getJSONArray("children");
}
if(item.has("mappings")) {
mappings = item.getJSONArray("mappings");
}
if(item.has("enumerations")) {
enumerations = item.getJSONArray("enumerations");
}
if(item.has("condition")) {
condition = item.getJSONObject("condition");
}
if(item.has("maxOccurs") && item.getInt("maxOccurs") == 1) {
single = true;
}
return generate(name, attributes, children, mappings, condition, enumerations, single);
}
private String generate(String name, JSONArray attributes, JSONArray children, JSONArray mappings, JSONObject condition, JSONArray enumerations, boolean single) {
String result = "";
if(mappings != null && mappings.size() > 0) {
if(children != null && children.size() > 0) {
result += generateStructuralWithMappings(name, attributes, children, mappings, condition);
} else {
String conditionStart = null;
if(condition != null) {
conditionStart = generateConditionStart(condition);
}
if(conditionStart != null) {
result += conditionStart;
}
if(mappings.size() == 1) {
result += generateWithMappings(name, attributes, mappings, condition, enumerations, single);
} else {
result += generateWithMappingsConcat(name, attributes, condition, mappings);
}
if(conditionStart != null) {
result += "</xsl:if>";
}
}
} else {
result += generateWithNoMappings(name, attributes, children);
}
return result;
}
private String generateConditionStart(JSONObject condition) {
String conditionTest = null;
if(condition != null) {
// String conditionXPath = condition.getString("xpath");
// String conditionValue = condition.getString("value");
// String testXPath = (normaliseXPath(conditionXPath));
conditionTest = generateConditionTest(condition);
if(conditionTest != null && conditionTest.length() > 0) {
return "<xsl:if test=\"" + conditionTest + "\">";
}
}
return null;
}
private String logicalOpXSLTRepresentation(String logicalop) {
if(logicalop != null) {
if(logicalop.equalsIgnoreCase("AND")) {
return "and";
} else if(logicalop.equalsIgnoreCase("OR")) {
return "or";
}
}
return "and";
}
private boolean isUnaryOperator(String operator) {
if(operator.equals("EXISTS") || operator.equals("NOTEXISTS")) {
return true;
} else {
return false;
}
}
private boolean isFunctionOperator(String operator) {
if(operator.equals("CONTAINS") || operator.equals("STARTSWITH") || operator.equals("ENDSWITH")) {
return true;
} else {
return false;
}
}
private String relationalOpXSLTRepresentation(String relationalop) {
if(relationalop != null) {
if(relationalop.equalsIgnoreCase("EQ")) {
return "=";
} else if(relationalop.equalsIgnoreCase("NEQ")) {
return "!=";
}
}
return "=";
}
private String generateConditionTest(JSONObject condition) {
String result = "";
if(condition != null) {
if(condition.has("clauses") && condition.has("logicalop")) {
String logicalop = condition.getString("logicalop");
String clauseTest = "";
JSONArray clauses = condition.getJSONArray("clauses");
Iterator i = clauses.iterator();
while(i.hasNext()) {
JSONObject clause = (JSONObject) i.next();
String test = generateConditionTest(clause);
if(test.length() > 0) {
if(clauseTest.length() > 0) {
clauseTest += " " + logicalOpXSLTRepresentation(logicalop) + " ";
}
clauseTest += "(" + test + ")";
}
}
result += clauseTest;
} else {
String relationalOp = "EQ";
String conditionOp = "=";
if(condition.has("relationalop")) {
relationalOp = condition.getString("relationalop");
conditionOp = relationalOpXSLTRepresentation(relationalOp);
}
if(isUnaryOperator(relationalOp)) {
if(condition.has("xpath")) {
String conditionXPath = condition.getString("xpath");
if(conditionXPath.length() > 0) {
String testXPath = (normaliseXPath(conditionXPath));
if(conditionOp.equals("EXISTS")) {
result += testXPath;
} else if (conditionOp.equals("NOTEXISTS")) {
result += "not(" + testXPath + ")";
}
}
}
} else if(isFunctionOperator(relationalOp)) {
if(condition.has("xpath") && condition.has("value")) {
String conditionXPath = condition.getString("xpath");
String conditionValue = condition.getString("value");
if(conditionXPath.length() > 0) {
String testXPath = (normaliseXPath(conditionXPath));
if(relationalOp.equals("CONTAINS")) {
result = "contains(" + testXPath + ",'" + escapeConstant(conditionValue) + "')";
} else if(relationalOp.equals("STARTSWITH")) {
result = "starts-with(" + testXPath + ",'" + escapeConstant(conditionValue) + "')";
} else if(relationalOp.equals("ENDSWITH")) {
result = "ends-with(" + testXPath + ",'" + escapeConstant(conditionValue) + "')";
}
}
}
} else {
if(condition.has("xpath") && condition.has("value")) {
String conditionXPath = condition.getString("xpath");
String conditionValue = condition.getString("value");
if(conditionXPath.length() > 0) {
String testXPath = (normaliseXPath(conditionXPath));
result += testXPath + " " + conditionOp + " '" + escapeConstant(conditionValue) + "'";
}
}
}
}
}
return result;
}
private String generateStructuralWithMappings(String name, JSONArray attributes, JSONArray children, JSONArray mappings, JSONObject condition) {
String result = "";
Iterator emi = mappings.iterator();
while(emi.hasNext()) {
JSONObject elementMapping = (JSONObject) emi.next();
String elementMappingType = (String) elementMapping.getString("type");
String elementMappingValue = (String) elementMapping.getString("value");
String expath = "";
String conditionStart = null;
if(elementMappingType.equalsIgnoreCase("xpath")) {
expath = (normaliseXPath(elementMappingValue));
result += "<xsl:for-each select=\"" + expath + "\">";
xpathPrefix.push(elementMappingValue);
conditionStart = generateConditionStart(condition);
if(conditionStart != null) {
result += conditionStart;
}
result += "<" + name + ">";
}
result += generateAttributes(attributes, elementMappingValue);
result += generateChildren(children);
if(elementMappingType.equalsIgnoreCase("xpath")) {
xpathPrefix.pop();
result += "</" + name + ">";
if(conditionStart != null) {
result += "</xsl:if>";
}
result += "</xsl:for-each>";
}
}
return result;
}
private String generateChildren(JSONArray children) {
String result = "";
if(children != null && children.size() > 0) {
Iterator ci = children.iterator();
while(ci.hasNext()) {
JSONObject child = (JSONObject) ci.next();
result += generate(child);
}
}
return result;
}
private String generateAttributes(JSONArray attributes) {
return generateAttributes(attributes, null);
}
private String generateAttributes(JSONArray attributes, String normaliseBy) {
String result = "";
if(attributes != null && attributes.size() > 0) {
Iterator ai = attributes.iterator();
while(ai.hasNext()) {
JSONObject attribute = (JSONObject) ai.next();
String name = attribute.getString("name");
String prefix = null;
if(attribute.has("prefix")) {
prefix = attribute.getString("prefix");
}
if(attribute.has("mappings")) {
JSONObject condition = null;
if(attribute.has("condition")) {
condition = attribute.getJSONObject("condition");
}
String conditionStart = null;
if(condition != null) {
conditionStart = generateConditionStart(condition);
}
if(conditionStart != null) {
result += conditionStart;
}
JSONArray amappings = attribute.getJSONArray("mappings");
if(amappings != null && amappings.size() > 0) {
JSONObject attributeMapping = (JSONObject) amappings.get(0);
String attributeMappingType = (String) attributeMapping.getString("type");
String attributeMappingValue = (String) attributeMapping.getString("value");
String axpath = "";
result += "<xsl:attribute name=\"" + ((prefix != null)?prefix + ":":"") + name.substring(1) + "\">";
result += generateAttributeMappings(amappings);
result += "</xsl:attribute>";
} else if(attribute.has("default")) {
result += "<xsl:attribute name=\"" + ((prefix != null)?prefix + ":":"") + name.substring(1) + "\">";
result += attribute.getString("default");
result += "</xsl:attribute>";
}
/*
else if(attribute.has("minOccurs")) {
String minOccurs = attribute.getString("minOccurs");
if(minOccurs.length() > 0) {
result += "<xsl:attribute name=\"" + ((prefix != null)?prefix + ":":"") + name.substring(1) + "\">";
result += "</xsl:attribute>";
}
}
*/
if(conditionStart != null) {
result += "</xsl:if>";
}
}
}
}
return result;
}
private String generateWithNoMappings(String name, JSONArray attributes, JSONArray children) {
String result = "<" + name + ">";
result += generateAttributes(attributes);
result += generateChildren(children);
result += "</" + name + ">";
return result;
}
private String generateWithMappings(String name, JSONArray attributes, JSONArray mappings) {
return generateWithMappings(name, attributes, mappings, false);
}
private String generateWithMappings(String name, JSONArray attributes, JSONArray mappings, boolean single) {
return generateWithMappings(name, attributes, mappings, null, null, single);
}
private String generateWithMappings(String name, JSONArray attributes, JSONArray mappings, JSONObject condition, JSONArray enumerations, boolean single) {
String result = "";
Iterator emi = mappings.iterator();
while(emi.hasNext()) {
JSONObject elementMapping = (JSONObject) emi.next();
String elementMappingType = (String) elementMapping.getString("type");
String elementMappingValue = (String) elementMapping.getString("value");
String expath = "";
if(elementMappingType.equalsIgnoreCase("xpath")) {
expath = (normaliseXPath(elementMappingValue));
xpathPrefix.push(elementMappingValue);
String conditionTest = this.generateConditionTest(condition);
if(conditionTest.length() > 0) { expath += "[" + conditionTest + "]"; }
// tokenize function block start
if(elementMapping.has("func") && elementMapping.getJSONObject("func").has("call") && elementMapping.getJSONObject("func").getString("call").equalsIgnoreCase("tokenize")) {
JSONObject func = elementMapping.getJSONObject("func");
String delimeter = ",";
if(func.has("arguments") && func.getJSONArray("arguments").size() > 0) {
delimeter = escapeConstant(func.getJSONArray("arguments").getString(0));
}
result += "<xsl:for-each select=\"tokenize(" + expath + "[1],'" + delimeter + "')\">";
} else {
result += "<xsl:for-each select=\"" + expath + "\">";
}
// tokenize function block end
if(single) {
result += "<xsl:if test=\"position() = 1\">";
}
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
String varname = "map" + (variablesCount++);
JSONArray valuemap = elementMapping.getJSONArray("valuemap");
variables.append("<xsl:variable name=\"" + varname + "\">");
Iterator i = valuemap.iterator();
while(i.hasNext()) {
JSONObject vm = (JSONObject) i.next();
if(vm.has("input") && vm.has("output")) {
String input = StringEscapeUtils.escapeXml(vm.getString("input"));
String output = StringEscapeUtils.escapeXml(vm.getString("output"));
variables.append("<map value=\"" + output + "\">" + input.trim() + "</map>");
}
}
variables.append("</xsl:variable>");
String indexVar = "idx" + (variablesCount++);
result += "<xsl:variable name=\"" + indexVar + "\" select=\"index-of($" + varname + "/map, normalize-space())\"/>";
result += "<xsl:choose>";
result += "<xsl:when test=\"$" + indexVar + " > 0\">";
result += "<" + name + ">";
result += "<xsl:value-of select=\"$" + varname + "/map[$" + indexVar + "]/@value\"/>";
result += "</" + name + ">";
result += "</xsl:when>";
result += "<xsl:otherwise>";
}
if(enumerations != null) {
String varname = "var" + (variablesCount++);
variables.append("<xsl:variable name=\"" + varname + "\">");
Iterator i = enumerations.iterator();
while(i.hasNext()) {
String e = (String) i.next();
e = StringEscapeUtils.escapeXml(e);
variables.append("<item>" + e + "</item>");
}
variables.append("</xsl:variable>");
result += "<xsl:if test=\"index-of($" + varname + "/item, normalize-space()) > 0\">";
}
result += "<" + name + ">";
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += "<" + name + ">";
}
result += generateAttributes(attributes, elementMappingValue);
if(elementMappingType.equalsIgnoreCase("xpath")) {
xpathPrefix.pop();
if(elementMapping.has("func")) {
result += applyXPathFunction(elementMapping.getJSONObject("func"));
} else {
result += "<xsl:value-of select=\".\"/>";
}
result += "</" + name + ">";
if(enumerations != null) {
result += "</xsl:if>";
}
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
result += "</xsl:otherwise>";
result += "</xsl:choose>";
}
if(single) {
result += "</xsl:if>";
}
result += "</xsl:for-each>";
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += StringEscapeUtils.escapeXml(elementMappingValue);
result += "</" + name + ">";
}
}
return result;
}
private String applyXPathFunction(JSONObject func)
{
String result = "<xsl:value-of select=\".\"/>";
if(func.has("call") && func.has("arguments")) {
String call = func.getString("call");
JSONArray args = func.getJSONArray("arguments");
JSONArray arguments = new JSONArray();
for(int a = 0; a < args.size(); a++) {
arguments.add(escapeConstant(args.getString(a)));
}
if(call.equalsIgnoreCase("substring")) {
result = "<xsl:value-of select=\"substring(.," + arguments.getString(0) + "," + arguments.getString(1) + ")\"/>";
} else if(call.equalsIgnoreCase("substring-after")) {
result = "<xsl:value-of select=\"substring-after(.,'" + arguments.getString(0) + "')\"/>";
} else if(call.equalsIgnoreCase("substring-before")) {
result = "<xsl:value-of select=\"substring-before(.,'" + arguments.getString(0) + "')\"/>";
} else if(call.equalsIgnoreCase("substring-between")) {
result = "<xsl:value-of select=\"substring-before(substring-after(.,'" + arguments.getString(0) + "'), '" + arguments.getString(1) + "')\"/>";
} else if(call.equalsIgnoreCase("split")) {
// how can you split in xsl ???
String varname = "split";
result = "<xsl:variable name=\"" + varname + "\" select=\"tokenize(.,'" + arguments.getString(0) + "')\"/>";
result += "<xsl:value-of select=\"$" + varname + "[" + arguments.getString(1) +"]\"/>";
} else if(call.equalsIgnoreCase("custom")) {
result = "<xsl:value-of select=\"" + arguments.getString(0) + "\"/>";
} else {
result = "<xsl:value-of select=\".\"/>";
}
}
return result;
}
/*
private String generateWithMappings(String name, JSONArray attributes, JSONArray mappings, boolean single) {
String result = "";
Iterator emi = mappings.iterator();
while(emi.hasNext()) {
JSONObject elementMapping = (JSONObject) emi.next();
String elementMappingType = (String) elementMapping.getString("type");
String elementMappingValue = (String) elementMapping.getString("value");
String expath = "";
if(elementMappingType.equalsIgnoreCase("xpath")) {
expath = (normaliseXPath(elementMappingValue));
result += "<xsl:for-each select=\"" + expath + "\">";
if(single) {
result += "<xsl:if test=\"position() = 1\">";
}
result += "<" + name + ">";
xpathPrefix.push(elementMappingValue);
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += "<" + name + ">";
}
result += generateAttributes(attributes, elementMappingValue);
if(elementMappingType.equalsIgnoreCase("xpath")) {
xpathPrefix.pop();
result += "<xsl:value-of select=\".\"/>";
result += "</" + name + ">";
if(single) {
result += "</xsl:if>";
}
result += "</xsl:for-each>";
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += StringEscapeUtils.escapeXml(elementMappingValue);
result += "</" + name + ">";
}
}
return result;
}
*/
private String escapeConstant(String c) {
String result = c;
result = result.replace("*", "\\*");
result = result.replace("'", "''");
result = StringEscapeUtils.escapeXml(result);
return result;
}
private String generateAttributeMappings(JSONArray mappings) {
String result = "";
Iterator emi = mappings.iterator();
while(emi.hasNext()) {
JSONObject elementMapping = (JSONObject) emi.next();
String elementMappingType = (String) elementMapping.getString("type");
String elementMappingValue = (String) elementMapping.getString("value");
String expath = "";
if(elementMappingType.equalsIgnoreCase("xpath")) {
expath = (normaliseXPath(elementMappingValue));
result += "<xsl:for-each select=\"" + expath + "\">";
xpathPrefix.push(elementMappingValue);
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
String varname = "map" + (variablesCount++);
JSONArray valuemap = elementMapping.getJSONArray("valuemap");
variables.append("<xsl:variable name=\"" + varname + "\">");
Iterator i = valuemap.iterator();
while(i.hasNext()) {
JSONObject vm = (JSONObject) i.next();
if(vm.has("input") && vm.has("output")) {
String input = StringEscapeUtils.escapeXml(vm.getString("input"));
String output = StringEscapeUtils.escapeXml(vm.getString("output"));
variables.append("<map value=\"" + output + "\">" + input.trim() + "</map>");
}
}
variables.append("</xsl:variable>");
String indexVar = "idx" + (variablesCount++);
result += "<xsl:variable name=\"" + indexVar + "\" select=\"index-of($" + varname + "/map, normalize-space())\"/>";
result += "<xsl:choose>";
result += "<xsl:when test=\"$" + indexVar + " > 0\">";
result += "<xsl:value-of select=\"$" + varname + "/map[$" + indexVar + "]/@value\"/>";
result += "</xsl:when>";
result += "<xsl:otherwise>";
}
}
if(elementMappingType.equalsIgnoreCase("xpath")) {
if(elementMapping.has("func")) {
result += applyXPathFunction(elementMapping.getJSONObject("func"));
} else {
result += "<xsl:if test=\"position() = 1\">";
result += "<xsl:value-of select=\".\"/>";
result += "</xsl:if>";
}
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
result += "</xsl:otherwise>";
result += "</xsl:choose>";
}
result += "</xsl:for-each>";
xpathPrefix.pop();
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += StringEscapeUtils.escapeXml(elementMappingValue);
}
}
return result;
}
private String generateWithMappingsConcat(String name, JSONArray attributes, JSONArray mappings) {
return generateWithMappingsConcat(name, attributes, null, mappings);
}
private String generateWithMappingsConcat(String name, JSONArray attributes, JSONObject condition, JSONArray mappings) {
String result = "";
result += "<" + name + ">";
result += generateAttributes(attributes);
Iterator emi = mappings.iterator();
while(emi.hasNext()) {
JSONObject elementMapping = (JSONObject) emi.next();
String elementMappingType = (String) elementMapping.getString("type");
String elementMappingValue = (String) elementMapping.getString("value");
String expath = "";
if(elementMappingType.equalsIgnoreCase("xpath")) {
expath = (normaliseXPath(elementMappingValue));
xpathPrefix.push(elementMappingValue);
String conditionTest = this.generateConditionTest(condition);
if(conditionTest.length() > 0) { expath += "[" + conditionTest + "]"; }
result += "<xsl:for-each select=\"" + expath + "\">";
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
String varname = "map" + (variablesCount++);
JSONArray valuemap = elementMapping.getJSONArray("valuemap");
variables.append("<xsl:variable name=\"" + varname + "\">");
Iterator i = valuemap.iterator();
while(i.hasNext()) {
JSONObject vm = (JSONObject) i.next();
if(vm.has("input") && vm.has("output")) {
String input = StringEscapeUtils.escapeXml(vm.getString("input"));
String output = StringEscapeUtils.escapeXml(vm.getString("output"));
variables.append("<map value=\"" + output + "\">" + input.trim() + "</map>");
}
}
variables.append("</xsl:variable>");
String indexVar = "idx" + (variablesCount++);
result += "<xsl:variable name=\"" + indexVar + "\" select=\"index-of($" + varname + "/map, normalize-space())\"/>";
result += "<xsl:choose>";
result += "<xsl:when test=\"$" + indexVar + " > 0\">";
result += "<xsl:value-of select=\"$" + varname + "/map[$" + indexVar + "]/@value\"/>";
result += "</xsl:when>";
result += "<xsl:otherwise>";
}
if(elementMapping.has("func")) {
result += applyXPathFunction(elementMapping.getJSONObject("func"));
} else {
result += "<xsl:value-of select=\".\"/>";
}
if(elementMapping.has("valuemap") && elementMapping.getJSONArray("valuemap").size() > 0) {
result += "</xsl:otherwise>";
result += "</xsl:choose>";
}
result += "</xsl:for-each>";
xpathPrefix.pop();
} else if(elementMappingType.equalsIgnoreCase("constant")) {
result += StringEscapeUtils.escapeXml(elementMappingValue);
}
}
result += "</" + name + ">";
return result;
}
private boolean descendantHasMappings(JSONObject item) {
JSONArray mappings = item.getJSONArray("mappings");
if(mappings != null && mappings.size() > 0) {
//System.out.println(item.get("name") + "hasMappings");
return true;
} else {
if(item.has("children")) {
JSONArray children = item.getJSONArray("children");
if(children != null && children.size() > 0) {
Iterator ci = children.iterator();
while(ci.hasNext()) {
JSONObject child = (JSONObject) ci.next();
if(this.descendantHasMappings(child)) {
//System.out.println(item.get("name") + "has child " + child.get("name") + " that has Mappings");
return true;
}
}
}
}
if(item.has("attributes")) {
JSONArray attributes = item.getJSONArray("attributes");
if(attributes != null && attributes.size() > 0) {
Iterator ai = attributes.iterator();
while(ai.hasNext()) {
JSONObject attribute = (JSONObject) ai.next();
if(this.descendantHasMappings(attribute)) {
//System.out.println(item.get("name") + "has attribute " + attribute.get("name") + " that has Mappings");
return true;
}
}
}
}
}
return false;
}
private String normaliseXPath(String string) {
String result = string;
//string.replaceFirst(this.root + "/", "");
if(!xpathPrefix.empty()) {
String prefix = xpathPrefix.peek();
if(result.indexOf(prefix) == 0) {
result = result.replaceFirst(prefix, "");
if(result.startsWith("/")) {
result = result.replaceFirst("/", "");
}
if(result.length() == 0) {
result = ".";
}
} else {
String[] tokens1 = string.split("/");
String[] tokens2 = prefix.split("/");
int commonStartIndex = -1;
for(int i = 0; i < tokens1.length; i++) {
if(tokens2.length > i) {
if(tokens1[i].equals(tokens2[i])) {
commonStartIndex++;
} else break;
}
}
if(commonStartIndex >= 0) {
result = "";
for(int i = 0; i < tokens2.length - commonStartIndex - 1; i++) {
if(result.length() > 0 && !result.endsWith("/")) { result += "/"; }
result += "..";
}
for(int i = commonStartIndex + 1; i < tokens1.length; i++) {
if(result.length() > 0 && !result.endsWith("/")) { result += "/"; }
result += tokens1[i];
}
}
}
}
return result;
}
public void setImportNamespaces(Map<String, String> namespaces) {
this.importNamespaces = namespaces;
}
}