/* FeatureIDE - An IDE to support feature-oriented software development * Copyright (C) 2005-2009 FeatureIDE Team, University of Magdeburg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * See http://www.fosd.de/featureide/ for further information. */ package featureide.fm.core.io.xml; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Iterator; import java.util.LinkedList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.prop4j.NodeWriter; import org.w3c.dom.Document; import org.w3c.dom.Node; import featureide.fm.core.Feature; import featureide.fm.core.FeatureModel; import featureide.fm.core.io.AbstractFeatureModelWriter; /** * TODO description * * @author Fabian Wielgorz */ public class XmlFeatureModelWriter extends AbstractFeatureModelWriter { public XmlFeatureModelWriter() { } /** * Creates a new writer and sets the feature model to write out. * * @param featureModel the structure to write */ public XmlFeatureModelWriter(FeatureModel featureModel) { setFeatureModel(featureModel); } /** * Creates the DOM Document Representation from the feature model fmodel * by using createXmlDocRec * @param doc Document where the feature model is put */ private void createXmlDoc(Document doc) { Node elem = doc.createElement("FeatureModel"); doc.appendChild(elem); createXmlDocRec(doc, elem, featureModel.getRoot()); createPropositionalConstraints(doc, elem); createAnnotations(doc, elem); } /** * Creates the DOM Document Representation from the feature model fmodel * by recursively building the Nodes * @param doc Document where the feature model is put * @param nod Current Node in the Document Tree * @param feat Current Feature in the feature model Tree */ private void createXmlDocRec(Document doc, Node nod, Feature feat) { Node nnod, fnod, tnod; LinkedList<Feature> children; if (feat == null) return; fnod = (feat.isMandatory())? doc.createElement("MFeature") : doc.createElement("Feature"); nod.appendChild(fnod); nnod = doc.createElement("Name"); fnod.appendChild(nnod); tnod = doc.createTextNode(feat.getName()); nnod.appendChild(tnod); children = feat.getChildren(); if (children.isEmpty()) return; if (feat.isAnd()) { nnod = doc.createElement("And"); } else if (feat.isOr()) { nnod = doc.createElement("Or"); } else if (feat.isAlternative()) { nnod = doc.createElement("Alternative"); } else System.out.println("creatXMlDockRec: Unexpected error!"); fnod.appendChild(nnod); Iterator<Feature> i = children.iterator(); while (i.hasNext()) { createXmlDocRec(doc, nnod ,i.next()); } } /** * Inserts the tags concerning propositional constraints into the DOM * document representation * @param doc * @param FeatMod Parent node for the propositonal nodes */ private void createPropositionalConstraints(Document doc, Node FeatMod) { if (featureModel.getPropositionalNodes().isEmpty()) return; Node propConstr = doc.createElement("PropositionalConstraints"); Node newNode, pConstr; FeatMod.appendChild(propConstr); newNode = doc.createTextNode("\n"); propConstr.appendChild(newNode); for (org.prop4j.Node node : featureModel.getPropositionalNodes()) { pConstr = doc.createElement("PConstraint"); propConstr.appendChild(pConstr); String nodeString = NodeWriter.nodeToString(node, NodeWriter.textualSymbols, true); if ((nodeString.startsWith("(")) && (nodeString.endsWith(")"))) { nodeString = nodeString.substring(1, nodeString.length() - 1); } newNode = doc.createTextNode(nodeString); pConstr.appendChild(newNode); } } private void createAnnotations(Document doc, Node FeatMod) { String annotationText = featureModel.getAnnotations(); if (annotationText == null) return; Node annotations = doc.createElement("Annotations"); Node newNode; FeatMod.appendChild(annotations); newNode = doc.createTextNode("\n" + annotationText + "\n"); annotations.appendChild(newNode); } /** * Inserts indentations into the text * @param text * @return */ private String prettyPrint (String text) { StringBuffer result = new StringBuffer(); String line; int indentLevel = 0; BufferedReader reader = new BufferedReader(new StringReader(text)); try { line = reader.readLine(); while (line != null) { if (line.startsWith("</")) { indentLevel--; for (int i=0; i < indentLevel; i++) { result.append(" "); } } else if (line.startsWith("<")) { for (int i=0; i < indentLevel; i++) { result.append(" "); } if (!line.contains("</")) { indentLevel++; } } else { for (int i=0; i < indentLevel; i++) { result.append(" "); } } result.append(line + "\n"); line = reader.readLine(); } } catch (IOException e) { e.printStackTrace(); } return result.toString(); } public String writeToString() { //Create Empty DOM Document DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); dbf.setIgnoringComments(true); dbf.setIgnoringElementContentWhitespace(false); dbf.setCoalescing(true); dbf.setExpandEntityReferences(true); DocumentBuilder db = null; try { db = dbf.newDocumentBuilder(); } catch (ParserConfigurationException pce) { System.err.println(pce); System.exit(1); } Document doc = db.newDocument(); //Create the Xml Representation createXmlDoc(doc); //Transform the Xml Representation into a String Transformer transfo = null; try { transfo = TransformerFactory.newInstance().newTransformer(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerFactoryConfigurationError e) { e.printStackTrace(); } transfo.setOutputProperty(OutputKeys.METHOD, "xml"); transfo.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(new StringWriter()); DOMSource source = new DOMSource(doc); try { transfo.transform(source, result); } catch (TransformerException e) { e.printStackTrace(); } return prettyPrint(result.getWriter().toString()); } }