/* * Copyright (c) 2013 Fraunhofer IGD * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Fraunhofer IGD */ package eu.esdihumboldt.hale.io.xslt.citygml; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import eu.esdihumboldt.hale.common.align.model.ChildContext; import eu.esdihumboldt.hale.common.align.model.Entity; import eu.esdihumboldt.hale.common.align.model.ParameterValue; import eu.esdihumboldt.hale.common.align.model.functions.RenameFunction; import eu.esdihumboldt.hale.common.align.model.impl.DefaultCell; import eu.esdihumboldt.hale.common.align.model.impl.DefaultProperty; import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition; import eu.esdihumboldt.hale.common.align.transformation.function.TransformationException; import eu.esdihumboldt.hale.common.core.io.IOProviderConfigurationException; import eu.esdihumboldt.hale.common.schema.SchemaSpaceID; import eu.esdihumboldt.hale.common.schema.model.ChildDefinition; import eu.esdihumboldt.hale.common.schema.model.PropertyDefinition; import eu.esdihumboldt.hale.io.gml.CityGMLConstants; import eu.esdihumboldt.hale.io.gml.geometry.GMLConstants; import eu.esdihumboldt.hale.io.xsd.model.XmlElement; import eu.esdihumboldt.hale.io.xsd.model.XmlIndex; import eu.esdihumboldt.hale.io.xslt.GroovyXslHelpers; import eu.esdihumboldt.hale.io.xslt.SourceContextProvider; import eu.esdihumboldt.hale.io.xslt.XsltConstants; import eu.esdihumboldt.hale.io.xslt.XsltExport; import eu.esdihumboldt.hale.io.xslt.XsltGenerationContext; import eu.esdihumboldt.hale.io.xslt.functions.XslVariable; import eu.esdihumboldt.hale.io.xslt.functions.impl.XslVariableImpl; /** * Specific XSLT export for mappings with a CityGML based schema as target * model. * * @author Simon Templer */ public class CityGMLXsltExport extends XsltExport implements CityGMLConstants, GMLConstants, XsltConstants { private SourceContextProvider sourceContext; private XmlElement targetCityModel; private XmlElement sourceCityModel; @Override protected void init(XmlIndex sourceIndex, XmlIndex targetIndex) throws IOProviderConfigurationException { super.init(sourceIndex, targetIndex); // scan target schema for CityModel targetCityModel = findCityModel(targetIndex); if (targetCityModel != null) { QName name = targetCityModel.getName(); setParameter(PARAM_ROOT_ELEMENT_NAMESPACE, new ParameterValue(name.getNamespaceURI())); setParameter(PARAM_ROOT_ELEMENT_NAME, new ParameterValue(name.getLocalPart())); } else { throw new IOProviderConfigurationException(MessageFormat .format("Element {0} not found in the target schema.", CITY_MODEL_ELEMENT)); } // scan source schema for CityModel sourceCityModel = findCityModel(sourceIndex); if (sourceCityModel != null) { // create a custom source context sourceContext = new CityGMLSourceContext(sourceCityModel); // TODO copy envelope? } } private XmlElement findCityModel(XmlIndex schema) { for (XmlElement element : schema.getElements().values()) { QName name = element.getName(); if (CITY_MODEL_ELEMENT.equals(name.getLocalPart()) && name.getNamespaceURI().startsWith(CITYGML_NAMESPACE_CORE)) { return element; } } return null; } @Override protected void writeContainerIntro(XMLStreamWriter writer, XsltGenerationContext context) throws XMLStreamException, IOException { if (targetCityModel != null && sourceCityModel != null) { // copy GML boundedBy // do it in a special template String template = context.reserveTemplateName("copyBoundedBy"); writer.writeStartElement(NS_URI_XSL, "call-template"); writer.writeAttribute("name", template); writer.writeEndElement(); // find source property PropertyDefinition sourceBB = null; for (ChildDefinition<?> child : sourceCityModel.getType().getChildren()) { if (child.asProperty() != null && child.getName().getLocalPart().equals("boundedBy") && child.getName().getNamespaceURI().startsWith(GML_NAMESPACE_CORE)) { sourceBB = child.asProperty(); break; } } // find target property PropertyDefinition targetBB = null; for (ChildDefinition<?> child : targetCityModel.getType().getChildren()) { if (child.asProperty() != null && child.getName().getLocalPart().equals("boundedBy") && child.getName().getNamespaceURI().startsWith(GML_NAMESPACE_CORE)) { targetBB = child.asProperty(); break; } } if (sourceBB != null && targetBB != null) { // create templated OutputStreamWriter out = new OutputStreamWriter( context.addInclude().openBufferedStream(), getCharset()); try { out.write("<xsl:template name=\"" + template + "\">"); StringBuilder selectSource = new StringBuilder(); selectSource.append('/'); selectSource.append( GroovyXslHelpers.asPrefixedName(sourceCityModel.getName(), context)); selectSource.append('/'); selectSource .append(GroovyXslHelpers.asPrefixedName(sourceBB.getName(), context)); selectSource.append("[1]"); out.write("<xsl:for-each select=\"" + selectSource.toString() + "\">"); String elementName = GroovyXslHelpers.asPrefixedName(targetBB.getName(), context); out.write("<" + elementName + ">"); // create bogus rename cell DefaultCell cell = new DefaultCell(); // source ListMultimap<String, Entity> source = ArrayListMultimap.create(); List<ChildContext> sourcePath = new ArrayList<ChildContext>(); sourcePath.add(new ChildContext(sourceBB)); PropertyEntityDefinition sourceDef = new PropertyEntityDefinition( sourceCityModel.getType(), sourcePath, SchemaSpaceID.SOURCE, null); source.put(null, new DefaultProperty(sourceDef)); cell.setSource(source); // target ListMultimap<String, Entity> target = ArrayListMultimap.create(); List<ChildContext> targetPath = new ArrayList<ChildContext>(); targetPath.add(new ChildContext(targetBB)); PropertyEntityDefinition targetDef = new PropertyEntityDefinition( targetCityModel.getType(), targetPath, SchemaSpaceID.TARGET, null); target.put(null, new DefaultProperty(targetDef)); cell.setTarget(target); // parameters ListMultimap<String, ParameterValue> parameters = ArrayListMultimap.create(); parameters.put(RenameFunction.PARAMETER_STRUCTURAL_RENAME, new ParameterValue("true")); parameters.put(RenameFunction.PARAMETER_IGNORE_NAMESPACES, new ParameterValue("true")); cell.setTransformationParameters(parameters); // variables ListMultimap<String, XslVariable> variables = ArrayListMultimap.create(); variables.put(null, new XslVariableImpl(sourceDef, ".")); try { out.write(context.getPropertyTransformation(RenameFunction.ID) .selectFunction(cell).getSequence(cell, variables, context, null)); } catch (TransformationException e) { throw new IllegalStateException( "Failed to create template for boundedBy copy.", e); } out.write("</" + elementName + ">"); out.write("</xsl:for-each>"); out.write("</xsl:template>"); } finally { out.close(); } } } } @Override protected SourceContextProvider getSourceContext() { return sourceContext; } }