package com.openMap1.mapper.converters;
import java.util.Iterator;
import java.util.StringTokenizer;
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 NHS_CDA_Converter extends NHS_CDA_Wrapper implements MapperWrapper{
//----------------------------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------------------------
/**
*
* @param ms set of mappings which uses this wrapper transform
* @param spare spare argument, just in case....
*/
public NHS_CDA_Converter(MappedStructure ms, Object spare) throws MapperException
{
super(ms,spare);
}
//----------------------------------------------------------------------------------------
// In-Wrapper Transform
//----------------------------------------------------------------------------------------
/**
* recursive descent, making the constrained CDA Element and its subtree from the
* corresponding element in the CDA document
* @param newTagName tag name to be given to the element in the result of the in-transformation
* @param cdaElement Element in the CDA xml structure
* @return Constrained element corresponding to the CDA element
*/
protected Element constrainedElement(String newTagName,Element cdaElement,ElementDef topElementDef)
throws MapperException
{
Element constrainedEl = moveInElementOnly(newTagName,cdaElement);
// add child Elements and recurse
for (Iterator<Element> ie = XMLUtil.childElements(cdaElement).iterator();ie.hasNext();)
{
Element cdaChild = ie.next();
// by taking the local name, you change tag names 'messageType' and 'contentId' the V3 namespace
String cdaName = XMLUtil.getLocalName(cdaChild);
String nextTagName = cdaName;
/* conversion of the tag name is needed if the current child element in the CDA has a child element
* contentId whose extension attribute defines a template */
String templateAtt = "";
Element contentChild = XMLUtil.firstNamedChild(cdaChild, "contentId");
if (contentChild != null) templateAtt = contentChild.getAttribute("extension");
/* typical form of templateAtt is 'COCD_TP145001UK03#AssignedAuthorSDS' (using a class name) */
if (!templateAtt.equals(""))
{
StringTokenizer st = new StringTokenizer(templateAtt,"#");
if (st.countTokens() != 2) throw new MapperException("In-wrapper transform: ContentId extension attribute '" + templateAtt + "' has not internal '#'");
st.nextToken();
String className = st.nextToken();
// this is the way I split tag names like 'entry' according to which template they lead to
nextTagName = cdaName + "_" + className;
}
Element constrainedChild = null;
// for <text> elements, save the child subtree in a table
if (nextTagName.equals("text")) constrainedChild = saveInputTextSubtree(cdaChild);
// for all other elements, recurse. The ElementDef is not used in this recursion
else constrainedChild = constrainedElement(nextTagName,cdaChild,topElementDef);
constrainedEl.appendChild(constrainedChild);
}
return constrainedEl;
}
//----------------------------------------------------------------------------------------
// Out-Wrapper Transform
//----------------------------------------------------------------------------------------
/**
* recursive descent, making the CDA Element and its subtree from the
* corresponding element in the translation result
* @param newTagName tag name to be given to the element in the result of the out-transformation
* @param resultElement Element in the translation output
* @return templated CDA element corresponding to the translation result element
*/
protected Element outWrappedV3Element(String newTagName,Element resultElement, ElementDef topElementDef)
throws MapperException
{
String tag = newTagName;
String uri = resultElement.getNamespaceURI();
/* put elements 'messageType' and contentId in the NHS namespace
* (there are usually no contentId elements in the in-wrapped instance; they are made below) */
if ((tag.equals("messageType")) || (tag.equals("contentId")))
{
tag = NHSPREFIX + ":" + tag;
uri = NHSURI;
}
/* if this element has a 'templateId' grandchild element,
* use its 'extension' attribute to shorten the name of this element -
* e.g converting 'entry_Finding' to 'entry' */
String ext = instanceGrandChildTemplateIdExtension(resultElement,true);
if ((ext != null) && (renamableTag(resultElement)))
{
StringTokenizer st = new StringTokenizer(ext,"#");
if (st.countTokens() != 2) throw new MapperException("Out-wrapper transform: templateId extension attribute '" + ext + "' has no internal '#'");
st.nextToken();
String className = st.nextToken();
// this is the way I split tag names like 'entry' according to which template they lead to
if (tag.endsWith("_" + className))
{
int newLength = tag.length() - className.length() - 1;
tag = tag.substring(0,newLength);
}
else // this can happen - some renamable tags do not get renamed, because they have no contentId child; but record it anyway
{
System.out.println("Tag name '" + tag + "' does not end with '" + className + "'");
}
}
// create the element in the out-wrapped document
Element cdaEl = outResultDoc.createElementNS(uri, tag);
// give it a contentId child if needed
giveContentIdChild(ext,cdaEl,resultElement);
// copy across all attributes to the templated CDA element, including namespace attributes
XMLUtil.copyAttributes(resultElement,cdaEl);
// add the NHS namespace declaration to the top element
if (newTagName.equals(topClassName))
cdaEl.setAttribute(("xmlns:" + NHSPREFIX),NHSURI);
// if there are no child elements, copy any text content
if (XMLUtil.childElements(resultElement).size() == 0)
XMLUtil.copyText(resultElement, cdaEl, outResultDoc);
// add child Elements and recurse
for (Iterator<Element> ie = XMLUtil.childElements(resultElement).iterator();ie.hasNext();)
{
Element constChild = ie.next();
String nextTagName = XMLUtil.getLocalName(constChild);
Element cdaChild = null;
// for text elements, recover the subtree from a hashtable stored by the input wrapper
if (nextTagName.equals("text")) cdaChild = recoverInputTextSubtree(constChild, "unknown CDA path");
// otherwise recurse (not using the ElementDef)
else cdaChild = outWrappedV3Element(nextTagName,constChild,topElementDef);
cdaEl.appendChild(cdaChild);
}
return cdaEl;
}
//----------------------------------------------------------------------------------------
// XSLT versions of wrapper transforms, for inclusion in full XSLT transforms
//----------------------------------------------------------------------------------------
protected String wrapperXSLFileName(boolean isIn)
{
if (isIn) return "wrapperXSLBase/NHSTemplatedInWrapper.xsl";
return "wrapperXSLBase/NHSTemplatedOutWrapper.xsl";
}
/**
* @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
{
super.addWrapperInTemplates(xout, templateFilter,true);
}
/**
* @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
{
super.addWrapperOutTemplates(xout, templateFilter,true);
}
}