package com.openMap1.mapper.converters; import java.util.Iterator; import org.eclipse.emf.common.util.EList; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.openMap1.mapper.ElementDef; import com.openMap1.mapper.MappedStructure; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.structures.MapperWrapper; import com.openMap1.mapper.util.XMLUtil; import com.openMap1.mapper.util.XSLOutputFile; import com.openMap1.mapper.writer.TemplateFilter; public class FACEWrapper extends AbstractMapperWrapper implements MapperWrapper{ public static String FACE_PREFIX = "face"; public static String FACE_URI = "http://schemas.facecode.com/webservices/2010/01/"; //---------------------------------------------------------------------------------------- // Constructor and initialisation from the Ecore model //---------------------------------------------------------------------------------------- public FACEWrapper(MappedStructure ms, Object spare) throws MapperException { super(ms,spare); } /** * @return the file extension of the outer document, with initial '*.' */ public String fileExtension() {return ("*.xml");} /** * @return the type of document transformed to and from; * see static constants in class AbstractMapperWrapper. */ public int transformType() {return AbstractMapperWrapper.XML_TYPE;} //---------------------------------------------------------------------------------------- // In-wrapper transform //---------------------------------------------------------------------------------------- @Override public Document transformIn(Object incoming) throws MapperException { if (!(incoming instanceof Element)) throw new MapperException("Document root is not an Element"); Element mappingRoot = (Element)incoming; String mappingRootPath = "/GetIndicativeBudget"; inResultDoc = XMLUtil.makeOutDoc(); Element inRoot = scanDocument(mappingRoot, mappingRootPath, AbstractMapperWrapper.IN_TRANSFORM); inResultDoc.appendChild(inRoot); return inResultDoc; } /** * default behaviour is a shallow copy - copying the element name, attributes, * and text content only if the element has no child elements. * to be overridden for specific paths in implementing classes */ protected Element inTransformNode(Element el, String path) throws MapperException { // copy the element with namespaces, prefixed tag name, attributes but no text or child Elements Element copy = (Element)inResultDoc.importNode(el, false); // convert <FaceCompletedItem> elements to specific types of item if (XMLUtil.getLocalName(el).equals("FaceCompletedItem")) { String questionCode = getPathValue(el,"QuestionId"); String newName = "FaceCompletedItem_" + questionCode; copy = renameElement(el, newName, true); } // if the source element has no child elements but has text, copy the text String text = textOnly(el); if (!text.equals("")) copy.appendChild(inResultDoc.createTextNode(text)); return copy; } //---------------------------------------------------------------------------------------- // Out-wrapper transform //---------------------------------------------------------------------------------------- @Override public Object transformOut(Element outgoing) throws MapperException { String mappingRootPath = "/Envelope"; outResultDoc = XMLUtil.makeOutDoc(); Element outRoot = scanDocument(outgoing, mappingRootPath, AbstractMapperWrapper.OUT_TRANSFORM); outResultDoc.appendChild(outRoot); return outResultDoc; } /** * default behaviour is a shallow copy - copying the element name, attributes, * and text content only if the element has no child elements. * to be overridden for specific paths in implementing classes */ protected Element outTransformNode(Element el, String path) throws MapperException { // copy the element with namespaces, prefixed tag name, attributes but no text or child Elements Element copy = (Element)outResultDoc.importNode(el, false); // convert specific types of <FaceCompletedItem_XX> back to plain <FACECompletedItem> if (XMLUtil.getLocalName(el).startsWith("FaceCompletedItem")) { copy = renameElement(el,"FaceCompletedItem",false); } // if the source element has no child elements but has text, copy the text String text = textOnly(el); if (!text.equals("")) copy.appendChild(outResultDoc.createTextNode(text)); return copy; } /** * copy an element and all its attributes to the new document, renaming it * and putting it in no namespace. * @param el * @param newName * @param isIn true for the in-transform, false for the out-transform * @return * @throws MapperException */ protected Element renameElement(Element el, String newName, boolean isIn) throws MapperException { Element newEl = null; if (isIn) newEl = inResultDoc.createElementNS(FACE_URI, newName); else if (!isIn) newEl = outResultDoc.createElementNS(FACE_URI, newName); // set all attributes of the constrained element, including namespace attributes for (int a = 0; a < el.getAttributes().getLength();a++) { Attr at = (Attr)el.getAttributes().item(a); newEl.setAttribute(at.getName(), at.getValue()); } return newEl; } //-------------------------------------------------------------------------------------------------------------- // XSLT Wrapper Transforms //-------------------------------------------------------------------------------------------------------------- /** * @param xout XSLT output being made * @param templateFilter a filter on the templates, implemented by XSLGeneratorImpl * append the templates and variables to be included in the XSL * to do the full transformation, to apply the wrapper transform in the 'in' direction. * Templates must have mode = "inWrapper" */ public void addWrapperInTemplates(XSLOutputFile xout, TemplateFilter templateFilter) throws MapperException { // see class AbstractMapperWrapper - adds a plain identity template super.addWrapperInTemplates(xout, templateFilter); // add the FACE namespace xout.topOut().setAttribute("xmlns:" + FACE_PREFIX, FACE_URI); for (Iterator<ElementDef> it = findFACEItemsElementDefs(ms()).iterator();it.hasNext();) { ElementDef FACEItem = it.next(); String tagName = FACEItem.getName(); if (tagName.startsWith("FaceCompletedItem_")) { String questionId = tagName.substring("FaceCompletedItem_".length()); addInTemplate(xout,tagName,questionId); } } } /** * @param xout XSLT output being made * @param templateFilter a filter on the templates to be included, implemented by XSLGeneratorImpl * append the templates and variables to be included in the XSL * to do the full transformation, to apply the wrapper transform in the 'out' direction. * Templates must have mode = "outWrapper" * @throws MapperException */ public void addWrapperOutTemplates(XSLOutputFile xout, TemplateFilter templateFilter) throws MapperException { // see class AbstractMapperWrapper - adds a plain identity template super.addWrapperOutTemplates(xout, templateFilter); // add the FACE namespace xout.topOut().setAttribute("xmlns:" + FACE_PREFIX, FACE_URI); for (Iterator<ElementDef> it = findFACEItemsElementDefs(ms()).iterator();it.hasNext();) { ElementDef FACEItem = it.next(); String tagName = FACEItem.getName(); if (tagName.startsWith("FaceCompletedItem_")) { String questionId = tagName.substring("FaceCompletedItem_".length()); addOutTemplate(xout,tagName,questionId); } } } /** * add an in-wrapper template of the form <xsl:template match="face:FaceCompletedItem[face:QuestionId='F14_14_46_11_15_33T61_38']" mode="inWrapper"> <face:FaceCompletedItem_F14_14_46_11_15_33T61_38> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="inWrapper"/> </face:FaceCompletedItem_F14_14_46_11_15_33T61_38> </xsl:template> * @param xout * @param tagName * @param questionId */ private void addInTemplate(XSLOutputFile xout,String tagName,String questionId) throws MapperException { Element tempEl = xout.XSLElement("template"); tempEl.setAttribute("match", FACE_PREFIX + ":FaceCompletedItem[" + FACE_PREFIX + ":QuestionId='" + questionId + "']"); tempEl.setAttribute("mode", "inWrapper"); Element FACEEl = xout.NSElement(FACE_PREFIX, tagName, FACE_URI); tempEl.appendChild(FACEEl); addApplyChildren(xout,FACEEl,"inWrapper"); xout.topOut().appendChild(tempEl); } /** * add an out-wrapper template of the form <xsl:template match="face:FaceCompletedItem_F14_14_46_11_15_33T61_38" mode="outWrapper"> <face:FaceCompletedItem> <xsl:copy-of select="@*"/> <xsl:apply-templates mode="outWrapper"/> </face:FaceCompletedItem> </xsl:template> * @param xout * @param tagName * @param questionId */ private void addOutTemplate(XSLOutputFile xout,String tagName,String questionId) throws MapperException { Element tempEl = xout.XSLElement("template"); tempEl.setAttribute("match", FACE_PREFIX + ":" + tagName); tempEl.setAttribute("mode", "outWrapper"); Element FACEEl = xout.NSElement(FACE_PREFIX, "FaceCompletedItem", FACE_URI); tempEl.appendChild(FACEEl); addApplyChildren(xout,FACEEl,"outWrapper"); xout.topOut().appendChild(tempEl); } /** * add two child nodes to a template to carry on copying down the tree * @param xout * @param FACEEl * @param mode * @throws MapperException */ private void addApplyChildren(XSLOutputFile xout,Element FACEEl, String mode) throws MapperException { Element copyOfEl = xout.XSLElement("copy-of"); copyOfEl.setAttribute("select", "@*"); FACEEl.appendChild(copyOfEl); Element applyEl = xout.XSLElement("apply-templates"); applyEl.setAttribute("mode", mode); FACEEl.appendChild(applyEl); } /** * * @param mappedStructure * @return a lit of nodes in the mapping set which are children of the 'Items' node * @throws MapperException */ public static EList<ElementDef> findFACEItemsElementDefs(MappedStructure mappedStructure) throws MapperException { ElementDef msRoot = mappedStructure.getRootElement(); if (msRoot == null) throw new MapperException("No root element in mapping set"); if (!msRoot.getName().equals("GetIndicativeBudget")) throw new MapperException("Root Element of mapping set must be called 'GetIndicativeBudget'"); // there must be a chain of child ElementDefs with the names below; throw an exception if not ElementDef payload = findChildElementDef(msRoot,"payload"); ElementDef items = findChildElementDef(payload,"Items"); return items.getChildElements(); } /** * * @param parent * @param childName * @return the child ElementDef with given name * @throws MapperException if it does not exist */ private static ElementDef findChildElementDef(ElementDef parent, String childName) throws MapperException { ElementDef child = parent.getNamedChildElement(childName); if (child == null) throw new MapperException("Mapping set node '" + parent.getName() + "' has no child '" + childName + "'"); return child; } }