/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.io.process; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.rapidminer.BreakpointListener; import com.rapidminer.Process; import com.rapidminer.ProcessContext; import com.rapidminer.RapidMiner; import com.rapidminer.operator.Annotations; import com.rapidminer.operator.ExecutionUnit; import com.rapidminer.operator.Operator; import com.rapidminer.operator.OperatorChain; import com.rapidminer.operator.OperatorVersion; import com.rapidminer.operator.ports.InputPort; import com.rapidminer.operator.ports.OutputPort; import com.rapidminer.operator.ports.OutputPorts; import com.rapidminer.tools.container.Pair; /** * * @author Simon Fischer */ public class XMLExporter { public static final String ELEMENT_PROCESS = "process"; private boolean onlyCoreElements = false; public XMLExporter() { this(false); } /** * * @param onlyCoreElements * If true, GUI and other additional information will be ignored. */ public XMLExporter(boolean onlyCoreElements) { this.onlyCoreElements = onlyCoreElements; } /** * This method will return append the description of this process to the given * father element. */ public void exportProcess(Element fatherElement, Process process) { Element rootElement = XMLTools.addTag(fatherElement, ELEMENT_PROCESS); rootElement.setAttribute("version", RapidMiner.getLongVersion()); Document doc = rootElement.getOwnerDocument(); rootElement.appendChild(exportProcessContext(process.getContext(), doc)); if (!process.getAnnotations().isEmpty()) { rootElement.appendChild(exportAnnotations(process.getAnnotations(), doc)); } rootElement.appendChild(exportOperator(process.getRootOperator(), false, doc)); } /** * This method will create a document, append the complete process that contains the given operator. * The {@link Document} is then returned. */ public Document exportProcess(Operator operator, boolean hideDefault) throws IOException { try { Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element rootElement = doc.createElement(ELEMENT_PROCESS); doc.appendChild(rootElement); rootElement.setAttribute("version", RapidMiner.getLongVersion()); final Process process = operator.getProcess(); if (process != null) { rootElement.appendChild(exportProcessContext(process.getContext(), doc)); if (!process.getAnnotations().isEmpty()) { rootElement.appendChild(exportAnnotations(process.getAnnotations(), doc)); } } rootElement.appendChild(exportOperator(operator, hideDefault, doc)); return doc; } catch (ParserConfigurationException e) { throw new IOException("Cannot create XML document builder: " + e, e); } } public Document exportSingleOperator(Operator operator) throws IOException { try { Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); doc.appendChild(exportOperator(operator, false, doc)); return doc; } catch (ParserConfigurationException e) { throw new IOException("Cannot create XML document builder: " + e, e); } } private Element exportOperator(Operator operator, boolean hideDefault, Document doc) { Element opElement = doc.createElement("operator"); opElement.setAttribute("name", operator.getName()); opElement.setAttribute("class", operator.getOperatorDescription().getKey()); OperatorVersion opVersion = operator.getCompatibilityLevel(); if (opVersion == null) { opVersion = OperatorVersion.getLatestVersion(operator.getOperatorDescription()); } opElement.setAttribute("compatibility", opVersion.toString()); StringBuilder breakpointString = new StringBuilder(); boolean first = true; for (int i = 0; i < BreakpointListener.BREAKPOINT_POS_NAME.length; i++) { if (operator.hasBreakpoint(i)) { if (first) { first = false; } else { breakpointString.append(","); } breakpointString.append(BreakpointListener.BREAKPOINT_POS_NAME[i]); } } if (!first) { opElement.setAttribute("breakpoints", breakpointString.toString()); } opElement.setAttribute("expanded", operator.isExpanded() ? "true" : "false"); opElement.setAttribute("activated", operator.isEnabled() ? "true" : "false"); String description = operator.getUserDescription(); if (description != null && description.length() > 0) { Element descrElem = doc.createElement("description"); descrElem.appendChild(doc.createTextNode(description)); opElement.appendChild(descrElem); } operator.getParameters().appendXML(opElement, hideDefault, doc); if (operator instanceof OperatorChain) { OperatorChain nop = (OperatorChain) operator; for (ExecutionUnit executionUnit : nop.getSubprocesses()) { opElement.appendChild(exportExecutionUnit(executionUnit, hideDefault, doc, false)); } } if (!onlyCoreElements) { ProcessXMLFilterRegistry.fireOperatorExported(operator, opElement); } // if (RapidMiner.getExecutionMode().hasMainFrame()) { // if (RapidMinerGUI.getMainFrame() != null) { // RapidMinerGUI.getMainFrame().getProcessPanel().getProcessRenderer().enrichOperatorElement(operator, opElement); // } // } return opElement; } private Element exportExecutionUnit(ExecutionUnit executionUnit, boolean hideDefault, Document doc, boolean isRoot) { Element procElement; if (isRoot) { procElement = doc.createElementNS(XMLTools.SCHEMA_URL_PROCESS, ELEMENT_PROCESS); // procElement.setAttribute("version", "5.0"); } else { procElement = doc.createElement(ELEMENT_PROCESS); } procElement.setAttribute("expanded", executionUnit.isExpanded() ? "true" : "false"); for (Operator op : executionUnit.getOperators()) { procElement.appendChild(exportOperator(op, hideDefault, doc)); } exportConnections(executionUnit.getInnerSources(), executionUnit, procElement, doc); for (Operator op : executionUnit.getOperators()) { exportConnections(op.getOutputPorts(), executionUnit, procElement, doc); } if (!onlyCoreElements) { ProcessXMLFilterRegistry.fireExecutionUnitExported(executionUnit, procElement); } // if (RapidMiner.getExecutionMode().hasMainFrame()) { // if (RapidMinerGUI.getMainFrame() != null) { // RapidMinerGUI.getMainFrame().getProcessPanel().getProcessRenderer().enrichProcessElement(executionUnit, procElement); // } // } return procElement; } private void exportConnections(OutputPorts outputPorts, ExecutionUnit processInScope, Element insertInto, Document doc) { for (OutputPort outputPort : outputPorts.getAllPorts()) { if (outputPort.isConnected()) { Element portElement = doc.createElement("connect"); if (processInScope.getEnclosingOperator() != outputPorts.getOwner().getOperator()) { portElement.setAttribute("from_op", outputPorts.getOwner().getOperator().getName()); } portElement.setAttribute("from_port", outputPort.getName()); InputPort destination = outputPort.getDestination(); if (processInScope.getEnclosingOperator() != destination.getPorts().getOwner().getOperator()) { portElement.setAttribute("to_op", destination.getPorts().getOwner().getOperator().getName()); } portElement.setAttribute("to_port", destination.getName()); insertInto.appendChild(portElement); } } } private static void appendList(Element element, String name, List<String> locations) { Document doc = element.getOwnerDocument(); Element list = doc.createElement(name); element.appendChild(list); // We don't write the last empty entries, so strip first. LinkedList<String> nonNull = new LinkedList<String>(locations); Collections.reverse(nonNull); Iterator<String> i = nonNull.iterator(); while (i.hasNext()) { String loc = i.next(); if (loc != null && !loc.isEmpty()) { break; } i.remove(); } Collections.reverse(nonNull); for (String loc : nonNull) { Element stringElem = doc.createElement("location"); list.appendChild(stringElem); stringElem.appendChild(doc.createTextNode(loc)); } } private Element exportProcessContext(ProcessContext context, Document doc) { Element element = doc.createElement("context"); appendList(element, "input", context.getInputRepositoryLocations()); appendList(element, "output", context.getOutputRepositoryLocations()); Element macrosElem = doc.createElement("macros"); element.appendChild(macrosElem); for (Pair<String, String> macro : context.getMacros()) { Element macroElement = doc.createElement("macro"); macrosElem.appendChild(macroElement); Element key = doc.createElement("key"); macroElement.appendChild(key); key.appendChild(doc.createTextNode(macro.getFirst())); Element value = doc.createElement("value"); macroElement.appendChild(value); value.appendChild(doc.createTextNode(macro.getSecond())); } return element; } private Element exportAnnotations(Annotations annotations, Document doc) { return annotations.toXML(doc); } }