package com.openMap1.mapper.util;
import java.util.Vector;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.openMap1.mapper.core.MapperException;
import com.openMap1.mapper.core.XMLException;
public class XSLOutputFile extends XMLOutputFile {
//---------------------------------------------------------------------------------------------------
// methods for XSLT files
//---------------------------------------------------------------------------------------------------
/**
* a prefix for the W3C XML schema namespace URI
*/
public String XSLPrefix = "xsl";
/**
* Make an Element in the W3C XML schema namespace, with prefix as defined by XSLPrefix.
* @param name the name after the prefix and ':'
* @return the new Element
* @throws XMLException
*/
public Element XSLElement(String name) throws XMLException
{
return XMLUtil.NSElement(outDoc(),XSLPrefix, name, XMLUtil.XSLURI);
}
/**
*
* @param name
* @param text
* @return an XSL element with text content
* @throws XMLException
*/
public Element XSLTextElement(String name, String text) throws XMLException
{
return XMLUtil.textNSElement(outDoc(), XSLPrefix, name, XMLUtil.XSLURI, text);
}
/**
* add a test template, of a form like:
*
<xsl:template match="*" mode="test">
<xsl:variable name="vTest" select="."/>
<xsl:message>local name: [<xsl:value-of select="local-name()"/>]</xsl:message>
<xsl:message>namespace uri: [<xsl:value-of select="namespace-uri()"/>]</xsl:message>
</xsl:template>
to be applied as in:
<xsl:apply-templates mode="test" select="$variable"/>
by hand-written additions to transforms, to get diagnostic information
about node-valued variables.
* @param xout
*/
public void addTestTemplate() throws MapperException
{
Element tempEl = XSLElement("template");
tempEl.setAttribute("match", "*");
tempEl.setAttribute("mode", "test");
Element varEl = XSLElement("variable");
varEl.setAttribute("name", "vTest");
varEl.setAttribute("select", ".");
tempEl.appendChild(varEl);
String diagnostic_1 = "local name: [<xsl:value-of select='local-name()'/>]";
Element messEl_1 = XSLTextElement("message", diagnostic_1);
tempEl.appendChild(messEl_1);
String diagnostic_2 = "namespace uri: [<xsl:value-of select='namespace-uri()''/>]";
Element messEl_2 = XSLTextElement("message", diagnostic_2);
tempEl.appendChild(messEl_2);
topOut().appendChild(tempEl);
}
/**
* add a parameter <xsl:param> to a template, if there is not
* a parameter or a variable of that name already.
* Return true if one was added.
*/
public boolean addParameter(String paramName, Element templateNode) throws XMLException
{
boolean res = false;
if ((!GenUtil.inVector(paramName, parameters(templateNode))) &&
(!GenUtil.inVector(paramName, allVariables(templateNode))))
{
Element paramEl = XSLElement("param");
paramEl.setAttribute("name", paramName);
NodeList nl = templateNode.getChildNodes();
Node first = nl.item(0);
templateNode.insertBefore(paramEl, first);
res = true;
}
return res;
}
/**
* Vector of names of parameters of the current template
*/
public Vector<String> parameters(Element templateNode)
{
Vector<String> params = new Vector<String>();
Vector<Element> defNodes = XMLUtil.namedChildElements(templateNode, "param");
for (int j = 0; j < defNodes.size(); j++) {
Element defNode = defNodes.elementAt(j);
params.addElement(defNode.getAttribute("name"));
}
return params;
}
/**
* Vector of names of variables declared at the top level of the current template
*/
public Vector<String> topVariables(Element templateNode)
{
Vector<String> vars = new Vector<String>();
Vector<Element> defNodes = XMLUtil.namedChildElements(templateNode, "variable");
for (int j = 0; j < defNodes.size(); j++) {
Element defNode = defNodes.elementAt(j);
vars.addElement(defNode.getAttribute("name"));
}
return vars;
}
/**
* Vector of names of variables declared at any level of the current template
*/
public Vector<String> allVariables(Element templateNode) {
Vector<String> vars = new Vector<String>();
Vector<Element> defNodes = XMLUtil.namedChildElements(templateNode, "variable");
// top level variables
for (int j = 0; j < defNodes.size(); j++) {
Element defNode = defNodes.elementAt(j);
vars.addElement(defNode.getAttribute("name"));
}
// variables declared inside other elements
Vector<Element> allNodes = childElements(templateNode);
for (int j = 0; j < allNodes.size(); j++) {
Element cNode = allNodes.elementAt(j);
Vector<String> childVars = allVariables(cNode);
for (int k = 0; k < childVars.size(); k++) {
vars.addElement(childVars.elementAt(k));
}
}
return vars;
}
/**
* check for a clashing variable or parameter name before adding it to a template
*/
public boolean clashes(String varName, Element templateNode) {
boolean clash = false;
if (GenUtil.inVector(varName, allVariables(templateNode))) clash = true;
if (GenUtil.inVector(varName, parameters(templateNode))) clash = true;
return clash;
}
/**
* true if the list of variables of the template has a variable made from a class name
* by appending something beginning with '_' to it.
*/
public boolean hasClassVar(String className, Element templateNode) {
boolean has = false;
Vector<String> vars = allVariables(templateNode);
for (int i = 0; i < vars.size(); i++) {
String var = vars.elementAt(i);
if (var.equals(className)) has = true; // used for subset = ""
if (var.startsWith(className + "_")) has = true; // used for all other subsets
}
return has;
}
/**
* If any variable declared beneath element toAdd clashes with any variable or parameter
* already declared under templateNode, return the name of the clashing variable.
* <p/>
* Otherwise return null.
*/
public String mergeClash(Element toAdd, Element templateNode) {
String clashVar = null;
Vector<String> addVars = allVariables(toAdd);
for (int i = 0; i < addVars.size(); i++) {
String vName = addVars.elementAt(i);
if (clashes(vName, templateNode)) clashVar = vName;
}
return clashVar;
}
/**
*
* @param parent Element to which an xsl:variable element is to be added
* @param varEl an xsl:variable element
*
* Add the xsl:variable element as a child of the parent element,
* before any xsl:call-template or xsl:apply-templates or xsl:if elements -
* to ensure variables are always declared before they are used, even when
* parameters are belatedly added to the calls and applies in the hookup process
*/
public void addVariableBeforeCallOrApply(Element parent, Element varEl)
{
NodeList nl = parent.getChildNodes();
boolean found = false;
for (int i = 0; i < nl.getLength(); i++)
{
Node next = nl.item(i);
if ((next instanceof Element) && (!found))
{
Element el = (Element)next;
if ((el.getLocalName().equals("call-template"))|
(el.getLocalName().equals("apply-templates"))|
(el.getLocalName().equals("if")))
{
parent.insertBefore(varEl, el);
found = true;
}
}
}
if (!found) parent.appendChild(varEl);
}
}