From ae94a7824458b7f3c1957740fc764978dd477b44 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Mon, 29 Jan 2018 12:27:52 +0100 Subject: [PATCH] parser of sbml function --- .../celldesigner/CellDesignerXmlParser.java | 1225 +++++++++-------- .../function/FunctionCollectionXmlParser.java | 24 + .../function/FunctionXmlParser.java | 44 + .../celldesigner/ComplexParserTests.java | 692 +++++----- .../function/FunctionXmlParserTest.java | 49 + converter-CellDesigner/testFiles/function.xml | 70 + .../testFiles/function/invalid_definition.xml | 2 + .../testFiles/function/invalid_math.xml | 4 + .../testFiles/function/simple.xml | 17 + 9 files changed, 1184 insertions(+), 943 deletions(-) create mode 100644 converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionCollectionXmlParser.java create mode 100644 converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java create mode 100644 converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParserTest.java create mode 100644 converter-CellDesigner/testFiles/function.xml create mode 100644 converter-CellDesigner/testFiles/function/invalid_definition.xml create mode 100644 converter-CellDesigner/testFiles/function/invalid_math.xml create mode 100644 converter-CellDesigner/testFiles/function/simple.xml diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java index 296e2bd330..05794c33d6 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParser.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringEscapeUtils; @@ -28,6 +29,7 @@ import lcsb.mapviewer.converter.InvalidInputDataExecption; import lcsb.mapviewer.converter.model.celldesigner.alias.AliasCollectionXmlParser; import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser; import lcsb.mapviewer.converter.model.celldesigner.compartment.CompartmentCollectionXmlParser; +import lcsb.mapviewer.converter.model.celldesigner.function.FunctionCollectionXmlParser; import lcsb.mapviewer.converter.model.celldesigner.reaction.ReactionCollectionXmlParser; import lcsb.mapviewer.converter.model.celldesigner.reaction.UnknownReactionClassException; import lcsb.mapviewer.converter.model.celldesigner.species.InternalModelSpeciesData; @@ -37,6 +39,7 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies; import lcsb.mapviewer.model.graphics.PolylineData; import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.SbmlFunction; import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.layout.graphics.Layer; import lcsb.mapviewer.model.map.layout.graphics.LayerOval; @@ -73,609 +76,621 @@ import lcsb.mapviewer.model.map.species.Species; */ public class CellDesignerXmlParser extends XmlParser implements IConverter { - /** - * Default class logger. - */ - private static Logger logger = Logger.getLogger(CellDesignerXmlParser.class.getName()); - - /** - * CellDesigner parser for layers. - */ - private LayerXmlParser layerParser = new LayerXmlParser(); - - /** - * CellDesigner parser for compartments collections. - */ - private CompartmentCollectionXmlParser compartmentCollectionXmlParser; - - /** - * CellDesigner parser for species collections. - */ - private SpeciesCollectionXmlParser speciesSbmlParser; - - /** - * CellDesigner parser for alias collections. - */ - private AliasCollectionXmlParser aliasCollectionParser; - - /** - * Annotation parser. - */ - private RestAnnotationParser rap = new RestAnnotationParser(); - - @Override - public Model createModel(ConverterParams params) throws InvalidInputDataExecption { - CellDesignerElementCollection elements = new CellDesignerElementCollection(); - - Model model = new ModelFullIndexed(null); - - if (params.getFilename() != null) { - model.setName(FilenameUtils.getBaseName(params.getFilename())); - } - speciesSbmlParser = new SpeciesCollectionXmlParser(elements); - aliasCollectionParser = new AliasCollectionXmlParser(elements, model); - compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); - - DOMParser parser = new DOMParser(); - try { - parser.parse(params.getSource()); - } catch (IOException e) { - throw new InvalidInputDataExecption("IO Problem with a file: " + params.getSource().getSystemId(), e); - } - Document doc = parser.getDocument(); - try { - - // Get the document's root XML node - NodeList root = doc.getChildNodes(); - - // Navigate down the hierarchy to get to the CEO node - Node sbmlNode = getNode("SBML", root); - if (sbmlNode == null) { - throw new InvalidInputDataExecption("No SBML node"); - } - - Node modelNode = getNode("model", sbmlNode.getChildNodes()); - if (modelNode == null) { - throw new InvalidInputDataExecption("No model node in SBML"); - } - // we ignore metaid - it's useless and obstruct data model - // model.setMetaId(getNodeAttr("metaId", modelNode)); - model.setIdModel(getNodeAttr("id", modelNode)); - - Node compartmentNode = getNode("listOfCompartments", modelNode.getChildNodes()); - if (compartmentNode != null) { - List<CellDesignerCompartment> compartments = compartmentCollectionXmlParser.parseXmlCompartmentCollection(compartmentNode); - elements.addElements(compartments); - } - - InternalModelSpeciesData modelData = new InternalModelSpeciesData(); - - Node speciesNode = getNode("listOfSpecies", modelNode.getChildNodes()); - if (speciesNode != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser.parseSbmlSpeciesCollection(speciesNode); - modelData.updateSpecies(species); - } - Node reactionsNode = null; - - NodeList nodes = modelNode.getChildNodes(); - for (int x = 0; x < nodes.getLength(); x++) { - Node node = nodes.item(x); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if (node.getNodeName().equalsIgnoreCase("annotation")) { - continue; - } else if (node.getNodeName().equalsIgnoreCase("listOfSpecies")) { - continue; - } else if (node.getNodeName().equalsIgnoreCase("listOfReactions")) { - reactionsNode = node; - } else if (node.getNodeName().equalsIgnoreCase("listOfCompartments")) { - // we already parsed compartemnts - continue; - } else if (node.getNodeName().equalsIgnoreCase("notes")) { - String notes = rap.getNotes(node); - if (notes != null) { - notes = StringEscapeUtils.unescapeHtml4(notes); - } - model.setNotes(notes); - } else if (node.getNodeName().equalsIgnoreCase("listOfUnitDefinitions")) { - continue; // we can ignore unit definitions - } else { - throw new InvalidInputDataExecption("Unknown element of model: " + node.getNodeName()); - } - } - } - - Node annotationNode = getNode("annotation", modelNode.getChildNodes()); - if (annotationNode == null) { - throw new InvalidInputDataExecption("No annotation node in SBML/model"); - } - - parseAnnotation(model, annotationNode, modelData, elements); - - if (speciesNode != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser.parseSbmlSpeciesCollection(speciesNode); - modelData.updateSpecies(species); - } - - if (reactionsNode != null) { - ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, params.isSbgnFormat()); - List<Reaction> reactions = reactionCollectionXmlParser.parseXmlReactionCollection(reactionsNode); - model.addReactions(reactions); - } - - if (params.isSizeAutoAdjust()) { - Rectangle2D bound = getModelBound(model); - double width = bound.getWidth() + 2 * (Math.max(0, bound.getX())); - double height = bound.getHeight() + 2 * (Math.max(0, bound.getY())); - - model.setWidth(width); - model.setHeight(height); - } - } catch (InvalidXmlSchemaException e) { - throw new InvalidInputDataExecption(e); - } catch (UnknownReactionClassException e) { - String type = e.getReactionType(); - String reactionId = e.getReactionId(); - String newType = null; - if ("CATALYSIS".equalsIgnoreCase(type)) { - newType = "positive influence"; - } else if ("INHIBITION".equalsIgnoreCase(type)) { - newType = "negative influence"; - } else if ("UNKNOWN_CATALYSIS".equalsIgnoreCase(type)) { - newType = "unknown positive influence"; - } else if ("UNKNOWN_INHIBITION".equalsIgnoreCase(type)) { - newType = "unknown negative influence"; - } else if ("PHYSICAL_STIMULATION".equalsIgnoreCase(type)) { - newType = "reduced physical stimulation"; - } else if ("MODULATION".equalsIgnoreCase(type)) { - newType = "reduced modulation"; - } else if ("TRIGGER".equalsIgnoreCase(type)) { - newType = "reduced trigger"; - } else { - throw new InvalidInputDataExecption(e); - } - throw new InvalidInputDataExecption( - "Reaction type \"" + type + "\" is inappropriate for reaction " + reactionId + ". Suggested type: " + newType - + " in the \"Reduced\" notation of CellDesigner.", - e); - } catch (CellDesignerParserException e) { - throw new InvalidInputDataExecption(e); - } - - return model; - } - - /** - * Computes bound of the model. - * - * @param model - * object for which computaion is done - * @return bound of the model - */ - Rectangle2D getModelBound(Model model) { - double maxX = 0; - double maxY = 0; - double minX = model.getWidth(); - double minY = model.getHeight(); - for (Element alias : model.getElements()) { - maxX = Math.max(maxX, alias.getWidth() + alias.getX()); - maxY = Math.max(maxY, alias.getHeight() + alias.getY()); - - minX = Math.min(minX, alias.getX()); - minY = Math.min(minY, alias.getY()); - - } - - for (Reaction reaction : model.getReactions()) { - for (Line2D line : reaction.getLines()) { - maxX = Math.max(maxX, line.getX1()); - maxX = Math.max(maxX, line.getX2()); - maxY = Math.max(maxY, line.getY1()); - maxY = Math.max(maxY, line.getY2()); - - minX = Math.min(minX, line.getX1()); - minX = Math.min(minX, line.getX2()); - minY = Math.min(minY, line.getY1()); - minY = Math.min(minY, line.getY2()); - } - } - - for (Layer layer : model.getLayers()) { - for (PolylineData lline : layer.getLines()) { - for (Line2D line : lline.getLines()) { - maxX = Math.max(maxX, line.getX1()); - maxX = Math.max(maxX, line.getX2()); - maxY = Math.max(maxY, line.getY1()); - maxY = Math.max(maxY, line.getY2()); - - minX = Math.min(minX, line.getX1()); - minX = Math.min(minX, line.getX2()); - minY = Math.min(minY, line.getY1()); - minY = Math.min(minY, line.getY2()); - } - } - for (LayerRect rect : layer.getRectangles()) { - maxX = Math.max(maxX, rect.getX()); - maxX = Math.max(maxX, rect.getX() + rect.getWidth()); - maxY = Math.max(maxY, rect.getY()); - maxY = Math.max(maxY, rect.getY() + rect.getHeight()); - - minX = Math.min(minX, rect.getX()); - minX = Math.min(minX, rect.getX() + rect.getWidth()); - minY = Math.min(minY, rect.getY()); - minY = Math.min(minY, rect.getY() + rect.getHeight()); - } - for (LayerOval oval : layer.getOvals()) { - maxX = Math.max(maxX, oval.getX()); - maxX = Math.max(maxX, oval.getX() + oval.getWidth()); - maxY = Math.max(maxY, oval.getY()); - maxY = Math.max(maxY, oval.getY() + oval.getHeight()); - - minX = Math.min(minX, oval.getX()); - minX = Math.min(minX, oval.getX() + oval.getWidth()); - minY = Math.min(minY, oval.getY()); - minY = Math.min(minY, oval.getY() + oval.getHeight()); - } - for (LayerText text : layer.getTexts()) { - maxX = Math.max(maxX, text.getX()); - maxX = Math.max(maxX, text.getX() + text.getWidth()); - maxY = Math.max(maxY, text.getY()); - maxY = Math.max(maxY, text.getY() + text.getHeight()); - - minX = Math.min(minX, text.getX()); - minX = Math.min(minX, text.getX() + text.getWidth()); - minY = Math.min(minY, text.getY()); - minY = Math.min(minY, text.getY() + text.getHeight()); - } - } - - Rectangle2D result = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); - return result; - } - - /** - * Parse annotation part of CellDesigner xml. - * - * @param model - * model that is parsed (and will be updated) - * @param modelData - * object conmtaining infoirmation about species during CellDesigner - * parsing - * @param elements - * collection of {@link CellDesignerElement cell designer elements} - * parsed from xml - * @param annotationNode - * xml node to parse - * @throws InvalidXmlSchemaException - * thrown when xmlString is invalid - */ - private void parseAnnotation(Model model, Node annotationNode, InternalModelSpeciesData modelData, CellDesignerElementCollection elements) - throws InvalidXmlSchemaException { - SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements); - - Node extensionNode = getNode("celldesigner:extension", annotationNode.getChildNodes()); - if (extensionNode == null) { - throw new InvalidXmlSchemaException("No celldesigner:extension node in SBML/model/annotation"); - } - - NodeList nodes = extensionNode.getChildNodes(); - Node includedSpecies = null; - Node listofSpeciesAlias = null; - Node listOfComplexSpeciesAlias = null; - Node listOfComparmentAlias = null; - Node listOfProteins = null; - Node listOfGenes = null; - Node listOfRnas = null; - Node listOfGroups = null; - Node listOfAntisenseRnas = null; - for (int x = 0; x < nodes.getLength(); x++) { - Node node = nodes.item(x); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if (node.getNodeName().equalsIgnoreCase("celldesigner:modelVersion")) { - // we ignore map version (there is no use for us) - // model.setVersion(getNodeValue(node)); - continue; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:modelDisplay")) { - model.setWidth(getNodeAttr("sizeX", node)); - model.setHeight(getNodeAttr("sizeY", node)); - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfSpeciesAliases")) { - listofSpeciesAlias = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfComplexSpeciesAliases")) { - listOfComplexSpeciesAlias = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfProteins")) { - listOfProteins = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfGenes")) { - listOfGenes = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfRNAs")) { - listOfRnas = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfAntisenseRNAs")) { - listOfAntisenseRnas = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfIncludedSpecies")) { - includedSpecies = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfCompartmentAliases")) { - listOfComparmentAlias = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfLayers")) { - model.addLayers(layerParser.parseLayers(node)); - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfGroups")) { - listOfGroups = node; - } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfBlockDiagrams")) { - layerParser.parseBlocks(model, node); - } else { - throw new InvalidXmlSchemaException("Unknown element of annotation: " + node.getNodeName()); - } - } - } - - if (listOfComparmentAlias != null) { - List<Compartment> aliases = aliasCollectionParser.parseXmlCompartmentAliasCollection(listOfComparmentAlias); - for (Element alias : aliases) { - rap.processNotes(alias); - model.addElement(alias); - } - } - - if (includedSpecies != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseIncludedSpeciesCollection(includedSpecies); - modelData.updateSpecies(species); - } - - if (listOfProteins != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlProteinCollection(listOfProteins); - modelData.updateSpecies(species); - } - if (listOfGenes != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlGeneCollection(listOfGenes); - modelData.updateSpecies(species); - } - if (listOfRnas != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlRnaCollection(listOfRnas); - modelData.updateSpecies(species); - } - if (listOfAntisenseRnas != null) { - List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlAntisenseRnaCollection(listOfAntisenseRnas); - modelData.updateSpecies(species); - } - - for (CellDesignerSpecies<?> species : modelData.getAll()) { - if (!species.getElementId().equals("")) { - elements.addElement(species); - } else { - logger.warn( - "Species (class: " + species.getClass().getName() + ", name: " + species.getName() - + ") exists in CD file, but is never instantiated. It's CellDesigner file problem."); - } - } - - if (listOfComplexSpeciesAlias != null) { - List<Complex> aliases = aliasCollectionParser.parseXmlComplexAliasCollection(listOfComplexSpeciesAlias); - for (Element alias : aliases) { - rap.processNotes(alias); - model.addElement(alias); - } - } - - if (listofSpeciesAlias != null) { - List<Species> aliases = aliasCollectionParser.parseXmlSpeciesAliasCollection(listofSpeciesAlias); - for (Element alias : aliases) { - rap.processNotes(alias); - model.addElement(alias); - } - } - - if (includedSpecies != null) { - parseAnnotationAliasesConnections(model, getNode("celldesigner:listOfSpeciesAliases", nodes)); - parseAnnotationComplexAliasesConnections(model, getNode("celldesigner:listOfComplexSpeciesAliases", nodes)); - } - - if (listOfGroups != null) { - layerParser.parseGroups(model, listOfGroups); - } - - } - - /** - * Parses celldesigner:listOfComplexSpeciesAliases node for annotation part of - * the CellDEsigner format. - * - * @param model - * model that is parsed - * @param aliasNode - * node to parse - * @throws InvalidXmlSchemaException - * thrown when xml node contains data that is not supported by xml - * schema - */ - void parseAnnotationComplexAliasesConnections(Model model, Node aliasNode) throws InvalidXmlSchemaException { - NodeList nodes = aliasNode.getChildNodes(); - for (int x = 0; x < nodes.getLength(); x++) { - Node node = nodes.item(x); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if (node.getNodeName().equalsIgnoreCase("celldesigner:complexSpeciesAlias")) { - String aliasId = getNodeAttr("id", node); - String complexId = getNodeAttr("complexSpeciesAlias", node); - Complex alias = model.getElementByElementId(aliasId); - if (alias == null) { - throw new InvalidXmlSchemaException("Alias does not exist " + aliasId); - } - Complex parentComplex = model.getElementByElementId(complexId); - if (parentComplex != null) { - parentComplex.addSpecies(alias); - alias.setComplex(parentComplex); - } - } else { - throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfComplexSpeciesAliases: " + node.getNodeName()); - } - } - } - - } - - /** - * Parses celldesigner:listOfSpeciesAliases node for annotation part of the - * CellDesigner format. - * - * @param model - * model that is parsed - * @param aliasNode - * node to parse - * @throws InvalidXmlSchemaException - * thrown when xml node contains data that is not supported by xml - * schema - */ - void parseAnnotationAliasesConnections(Model model, Node aliasNode) throws InvalidXmlSchemaException { - NodeList nodes = aliasNode.getChildNodes(); - for (int x = 0; x < nodes.getLength(); x++) { - Node node = nodes.item(x); - if (node.getNodeType() == Node.ELEMENT_NODE) { - if (node.getNodeName().equalsIgnoreCase("celldesigner:speciesAlias")) { - String aliasId = getNodeAttr("id", node); - String complexId = getNodeAttr("complexSpeciesAlias", node); - Element alias = model.getElementByElementId(aliasId); - if (alias == null) { - throw new InvalidXmlSchemaException("Alias does not exist " + aliasId); - } else if (alias instanceof Species) { - Species species = ((Species) alias); - Complex complex = model.getElementByElementId(complexId); - if (complex != null) { - species.setComplex(complex); - complex.addSpecies(species); - } - } - } else { - throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfSpeciesAliases: " + node.getNodeName()); - } - } - } - } - - /** - * Transforms model into CellDesigner xml. - * - * @param model - * model that should be transformed - * @return CellDesigner xml string for the model - * @throws InconsistentModelException - * thrown when then model is invalid - */ - public String toXml(Model model) throws InconsistentModelException { - CellDesignerElementCollection elements = new CellDesignerElementCollection(); - - SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); - ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, false); - aliasCollectionParser = new AliasCollectionXmlParser(elements, model); - - StringBuilder result = new StringBuilder(); - result.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - result.append( - "<sbml xmlns=\"http://www.sbml.org/sbml/level2/version4\" " - + "xmlns:celldesigner=\"http://www.sbml.org/2001/ns/celldesigner\" level=\"2\" version=\"4\">\n"); - // metaid is a strang cell designer id, usually it's model id and as far as - // we can tell it's not used at all - result.append("<model metaid=\"" + model.getIdModel() + "\" id=\"" + model.getIdModel() + "\">\n"); - - if (model.getNotes() != null) { - result.append("<notes>"); - result.append(escapeXml(model.getNotes())); - result.append("</notes>"); - } - - result.append(annotationToXml(model, elements)); - - compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); - - result.append(compartmentCollectionXmlParser.toXml(model.getCompartments())); - - result.append(speciesCollectionXmlParser.speciesCollectionToSbmlString(model.getSpeciesList())); - - result.append(reactionCollectionXmlParser.reactionCollectionToXmlString(model.getReactions())); - - result.append("</model>"); - result.append("</sbml>"); - return result.toString(); - } - - /** - * Generates xml node that should be in annotation part of the model. - * - * @param model - * model to transform - * @param elements - * collection of {@link CellDesignerElement cell designer elements} - * parsed from xml - * @return annotation xml string for the model - */ - private String annotationToXml(Model model, CellDesignerElementCollection elements) { - SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); - - StringBuilder result = new StringBuilder(); - result.append("<annotation>\n"); - result.append("<celldesigner:extension>\n"); - result.append("<celldesigner:modelVersion>4.0</celldesigner:modelVersion>\n"); - result.append("<celldesigner:modelDisplay sizeX=\"" + model.getWidth().intValue() + "\" sizeY=\"" + model.getHeight().intValue() + "\"/>\n"); - - result.append(speciesCollectionXmlParser.speciesCollectionToXmlIncludedString(model.getSpeciesList())); - - result.append(aliasCollectionParser.compartmentAliasCollectionToXmlString(model.getCompartments())); - result.append(aliasCollectionParser.complexAliasCollectionToXmlString(model.getComplexList())); - result.append(aliasCollectionParser.speciesAliasCollectionToXmlString(model.getNotComplexSpeciesList())); - - List<Protein> proteins = new ArrayList<>(); - List<Gene> genes = new ArrayList<>(); - List<Rna> rnas = new ArrayList<>(); - List<AntisenseRna> antisenseRnas = new ArrayList<>(); - for (Element element : model.getElements()) { - if (element instanceof Protein) { - proteins.add((Protein) element); - } else if (element instanceof Gene) { - genes.add((Gene) element); - } else if (element instanceof AntisenseRna) { - antisenseRnas.add((AntisenseRna) element); - } else if (element instanceof Rna) { - rnas.add((Rna) element); - } - } - - result.append(speciesCollectionXmlParser.proteinCollectionToXmlString(proteins)); - result.append(speciesCollectionXmlParser.geneCollectionToXmlString(genes)); - result.append(speciesCollectionXmlParser.rnaCollectionToXmlString(rnas)); - result.append(speciesCollectionXmlParser.antisenseRnaCollectionToXmlString(antisenseRnas)); - result.append(layerParser.layerCollectionToXml(model.getLayers())); - - result.append("</celldesigner:extension>\n"); - result.append("</annotation>\n"); - return result.toString(); - } - - @Override - public InputStream exportModelToInputStream(Model model) throws InconsistentModelException { - String exportedString = toXml(model); - InputStream inputStream = new ByteArrayInputStream(exportedString.getBytes()); - return inputStream; - } - - @Override - public File exportModelToFile(Model model, String filePath) throws InconsistentModelException, IOException { - File file = new File(filePath); - String exportedString = toXml(model); - FileWriter fileWriter = new FileWriter(file); - fileWriter.write(exportedString); - fileWriter.flush(); - fileWriter.close(); - - return file; - } - - @Override - public String getCommonName() { - return "CellDesigner SBML"; - } - - @Override - public MimeType getMimeType() { - return MimeType.SBML; - } - - @Override - public String getFileExtension() { - return "xml"; - } + /** + * Default class logger. + */ + private static Logger logger = Logger.getLogger(CellDesignerXmlParser.class.getName()); + + /** + * CellDesigner parser for layers. + */ + private LayerXmlParser layerParser = new LayerXmlParser(); + + /** + * CellDesigner parser for compartments collections. + */ + private CompartmentCollectionXmlParser compartmentCollectionXmlParser; + + /** + * CellDesigner parser for species collections. + */ + private SpeciesCollectionXmlParser speciesSbmlParser; + + /** + * CellDesigner parser for alias collections. + */ + private AliasCollectionXmlParser aliasCollectionParser; + + /** + * Annotation parser. + */ + private RestAnnotationParser rap = new RestAnnotationParser(); + + @Override + public Model createModel(ConverterParams params) throws InvalidInputDataExecption { + CellDesignerElementCollection elements = new CellDesignerElementCollection(); + FunctionCollectionXmlParser functionParser = new FunctionCollectionXmlParser(); + + Model model = new ModelFullIndexed(null); + + if (params.getFilename() != null) { + model.setName(FilenameUtils.getBaseName(params.getFilename())); + } + speciesSbmlParser = new SpeciesCollectionXmlParser(elements); + aliasCollectionParser = new AliasCollectionXmlParser(elements, model); + compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); + + DOMParser parser = new DOMParser(); + try { + parser.parse(params.getSource()); + } catch (IOException e) { + throw new InvalidInputDataExecption("IO Problem with a file: " + params.getSource().getSystemId(), e); + } + Document doc = parser.getDocument(); + try { + + // Get the document's root XML node + NodeList root = doc.getChildNodes(); + + // Navigate down the hierarchy to get to the CEO node + Node sbmlNode = getNode("SBML", root); + if (sbmlNode == null) { + throw new InvalidInputDataExecption("No SBML node"); + } + + Node modelNode = getNode("model", sbmlNode.getChildNodes()); + if (modelNode == null) { + throw new InvalidInputDataExecption("No model node in SBML"); + } + // we ignore metaid - it's useless and obstruct data model + // model.setMetaId(getNodeAttr("metaId", modelNode)); + model.setIdModel(getNodeAttr("id", modelNode)); + + Node compartmentNode = getNode("listOfCompartments", modelNode.getChildNodes()); + if (compartmentNode != null) { + List<CellDesignerCompartment> compartments = compartmentCollectionXmlParser + .parseXmlCompartmentCollection(compartmentNode); + elements.addElements(compartments); + } + + InternalModelSpeciesData modelData = new InternalModelSpeciesData(); + + Node speciesNode = getNode("listOfSpecies", modelNode.getChildNodes()); + if (speciesNode != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser + .parseSbmlSpeciesCollection(speciesNode); + modelData.updateSpecies(species); + } + Node reactionsNode = null; + Node functionsNode = null; + + NodeList nodes = modelNode.getChildNodes(); + for (int x = 0; x < nodes.getLength(); x++) { + Node node = nodes.item(x); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getNodeName().equalsIgnoreCase("annotation")) { + continue; + } else if (node.getNodeName().equalsIgnoreCase("listOfSpecies")) { + continue; + } else if (node.getNodeName().equalsIgnoreCase("listOfReactions")) { + reactionsNode = node; + } else if (node.getNodeName().equalsIgnoreCase("listOfCompartments")) { + // we already parsed compartments + continue; + } else if (node.getNodeName().equalsIgnoreCase("notes")) { + String notes = rap.getNotes(node); + if (notes != null) { + notes = StringEscapeUtils.unescapeHtml4(notes); + } + model.setNotes(notes); + } else if (node.getNodeName().equalsIgnoreCase("listOfUnitDefinitions")) { + continue; // we can ignore unit definitions + } else if (node.getNodeName().equalsIgnoreCase("listOfFunctionDefinitions")) { + functionsNode = node; + } else { + throw new InvalidInputDataExecption("Unknown element of model: " + node.getNodeName()); + } + } + } + + Node annotationNode = getNode("annotation", modelNode.getChildNodes()); + if (annotationNode == null) { + throw new InvalidInputDataExecption("No annotation node in SBML/model"); + } + + parseAnnotation(model, annotationNode, modelData, elements); + + if (speciesNode != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = speciesSbmlParser + .parseSbmlSpeciesCollection(speciesNode); + modelData.updateSpecies(species); + } + if (functionsNode!=null) { + model.addFunctions(functionParser.parseXmlFunctionCollection(functionsNode)); + } + + if (reactionsNode != null) { + ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, + params.isSbgnFormat()); + List<Reaction> reactions = reactionCollectionXmlParser.parseXmlReactionCollection(reactionsNode); + model.addReactions(reactions); + } + + if (params.isSizeAutoAdjust()) { + Rectangle2D bound = getModelBound(model); + double width = bound.getWidth() + 2 * (Math.max(0, bound.getX())); + double height = bound.getHeight() + 2 * (Math.max(0, bound.getY())); + + model.setWidth(width); + model.setHeight(height); + } + } catch (InvalidXmlSchemaException e) { + throw new InvalidInputDataExecption(e); + } catch (UnknownReactionClassException e) { + String type = e.getReactionType(); + String reactionId = e.getReactionId(); + String newType = null; + if ("CATALYSIS".equalsIgnoreCase(type)) { + newType = "positive influence"; + } else if ("INHIBITION".equalsIgnoreCase(type)) { + newType = "negative influence"; + } else if ("UNKNOWN_CATALYSIS".equalsIgnoreCase(type)) { + newType = "unknown positive influence"; + } else if ("UNKNOWN_INHIBITION".equalsIgnoreCase(type)) { + newType = "unknown negative influence"; + } else if ("PHYSICAL_STIMULATION".equalsIgnoreCase(type)) { + newType = "reduced physical stimulation"; + } else if ("MODULATION".equalsIgnoreCase(type)) { + newType = "reduced modulation"; + } else if ("TRIGGER".equalsIgnoreCase(type)) { + newType = "reduced trigger"; + } else { + throw new InvalidInputDataExecption(e); + } + throw new InvalidInputDataExecption("Reaction type \"" + type + "\" is inappropriate for reaction " + reactionId + + ". Suggested type: " + newType + " in the \"Reduced\" notation of CellDesigner.", e); + } catch (CellDesignerParserException e) { + throw new InvalidInputDataExecption(e); + } + + return model; + } + + /** + * Computes bound of the model. + * + * @param model + * object for which computaion is done + * @return bound of the model + */ + Rectangle2D getModelBound(Model model) { + double maxX = 0; + double maxY = 0; + double minX = model.getWidth(); + double minY = model.getHeight(); + for (Element alias : model.getElements()) { + maxX = Math.max(maxX, alias.getWidth() + alias.getX()); + maxY = Math.max(maxY, alias.getHeight() + alias.getY()); + + minX = Math.min(minX, alias.getX()); + minY = Math.min(minY, alias.getY()); + + } + + for (Reaction reaction : model.getReactions()) { + for (Line2D line : reaction.getLines()) { + maxX = Math.max(maxX, line.getX1()); + maxX = Math.max(maxX, line.getX2()); + maxY = Math.max(maxY, line.getY1()); + maxY = Math.max(maxY, line.getY2()); + + minX = Math.min(minX, line.getX1()); + minX = Math.min(minX, line.getX2()); + minY = Math.min(minY, line.getY1()); + minY = Math.min(minY, line.getY2()); + } + } + + for (Layer layer : model.getLayers()) { + for (PolylineData lline : layer.getLines()) { + for (Line2D line : lline.getLines()) { + maxX = Math.max(maxX, line.getX1()); + maxX = Math.max(maxX, line.getX2()); + maxY = Math.max(maxY, line.getY1()); + maxY = Math.max(maxY, line.getY2()); + + minX = Math.min(minX, line.getX1()); + minX = Math.min(minX, line.getX2()); + minY = Math.min(minY, line.getY1()); + minY = Math.min(minY, line.getY2()); + } + } + for (LayerRect rect : layer.getRectangles()) { + maxX = Math.max(maxX, rect.getX()); + maxX = Math.max(maxX, rect.getX() + rect.getWidth()); + maxY = Math.max(maxY, rect.getY()); + maxY = Math.max(maxY, rect.getY() + rect.getHeight()); + + minX = Math.min(minX, rect.getX()); + minX = Math.min(minX, rect.getX() + rect.getWidth()); + minY = Math.min(minY, rect.getY()); + minY = Math.min(minY, rect.getY() + rect.getHeight()); + } + for (LayerOval oval : layer.getOvals()) { + maxX = Math.max(maxX, oval.getX()); + maxX = Math.max(maxX, oval.getX() + oval.getWidth()); + maxY = Math.max(maxY, oval.getY()); + maxY = Math.max(maxY, oval.getY() + oval.getHeight()); + + minX = Math.min(minX, oval.getX()); + minX = Math.min(minX, oval.getX() + oval.getWidth()); + minY = Math.min(minY, oval.getY()); + minY = Math.min(minY, oval.getY() + oval.getHeight()); + } + for (LayerText text : layer.getTexts()) { + maxX = Math.max(maxX, text.getX()); + maxX = Math.max(maxX, text.getX() + text.getWidth()); + maxY = Math.max(maxY, text.getY()); + maxY = Math.max(maxY, text.getY() + text.getHeight()); + + minX = Math.min(minX, text.getX()); + minX = Math.min(minX, text.getX() + text.getWidth()); + minY = Math.min(minY, text.getY()); + minY = Math.min(minY, text.getY() + text.getHeight()); + } + } + + Rectangle2D result = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); + return result; + } + + /** + * Parse annotation part of CellDesigner xml. + * + * @param model + * model that is parsed (and will be updated) + * @param modelData + * object conmtaining infoirmation about species during CellDesigner + * parsing + * @param elements + * collection of {@link CellDesignerElement cell designer elements} + * parsed from xml + * @param annotationNode + * xml node to parse + * @throws InvalidXmlSchemaException + * thrown when xmlString is invalid + */ + private void parseAnnotation(Model model, Node annotationNode, InternalModelSpeciesData modelData, + CellDesignerElementCollection elements) throws InvalidXmlSchemaException { + SpeciesCollectionXmlParser parser = new SpeciesCollectionXmlParser(elements); + + Node extensionNode = getNode("celldesigner:extension", annotationNode.getChildNodes()); + if (extensionNode == null) { + throw new InvalidXmlSchemaException("No celldesigner:extension node in SBML/model/annotation"); + } + + NodeList nodes = extensionNode.getChildNodes(); + Node includedSpecies = null; + Node listofSpeciesAlias = null; + Node listOfComplexSpeciesAlias = null; + Node listOfComparmentAlias = null; + Node listOfProteins = null; + Node listOfGenes = null; + Node listOfRnas = null; + Node listOfGroups = null; + Node listOfAntisenseRnas = null; + for (int x = 0; x < nodes.getLength(); x++) { + Node node = nodes.item(x); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getNodeName().equalsIgnoreCase("celldesigner:modelVersion")) { + // we ignore map version (there is no use for us) + // model.setVersion(getNodeValue(node)); + continue; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:modelDisplay")) { + model.setWidth(getNodeAttr("sizeX", node)); + model.setHeight(getNodeAttr("sizeY", node)); + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfSpeciesAliases")) { + listofSpeciesAlias = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfComplexSpeciesAliases")) { + listOfComplexSpeciesAlias = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfProteins")) { + listOfProteins = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfGenes")) { + listOfGenes = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfRNAs")) { + listOfRnas = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfAntisenseRNAs")) { + listOfAntisenseRnas = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfIncludedSpecies")) { + includedSpecies = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfCompartmentAliases")) { + listOfComparmentAlias = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfLayers")) { + model.addLayers(layerParser.parseLayers(node)); + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfGroups")) { + listOfGroups = node; + } else if (node.getNodeName().equalsIgnoreCase("celldesigner:listOfBlockDiagrams")) { + layerParser.parseBlocks(model, node); + } else { + throw new InvalidXmlSchemaException("Unknown element of annotation: " + node.getNodeName()); + } + } + } + + if (listOfComparmentAlias != null) { + List<Compartment> aliases = aliasCollectionParser.parseXmlCompartmentAliasCollection(listOfComparmentAlias); + for (Element alias : aliases) { + rap.processNotes(alias); + model.addElement(alias); + } + } + + if (includedSpecies != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser + .parseIncludedSpeciesCollection(includedSpecies); + modelData.updateSpecies(species); + } + + if (listOfProteins != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlProteinCollection(listOfProteins); + modelData.updateSpecies(species); + } + if (listOfGenes != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlGeneCollection(listOfGenes); + modelData.updateSpecies(species); + } + if (listOfRnas != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser.parseXmlRnaCollection(listOfRnas); + modelData.updateSpecies(species); + } + if (listOfAntisenseRnas != null) { + List<Pair<String, ? extends CellDesignerSpecies<?>>> species = parser + .parseXmlAntisenseRnaCollection(listOfAntisenseRnas); + modelData.updateSpecies(species); + } + + for (CellDesignerSpecies<?> species : modelData.getAll()) { + if (!species.getElementId().equals("")) { + elements.addElement(species); + } else { + logger.warn("Species (class: " + species.getClass().getName() + ", name: " + species.getName() + + ") exists in CD file, but is never instantiated. It's CellDesigner file problem."); + } + } + + if (listOfComplexSpeciesAlias != null) { + List<Complex> aliases = aliasCollectionParser.parseXmlComplexAliasCollection(listOfComplexSpeciesAlias); + for (Element alias : aliases) { + rap.processNotes(alias); + model.addElement(alias); + } + } + + if (listofSpeciesAlias != null) { + List<Species> aliases = aliasCollectionParser.parseXmlSpeciesAliasCollection(listofSpeciesAlias); + for (Element alias : aliases) { + rap.processNotes(alias); + model.addElement(alias); + } + } + + if (includedSpecies != null) { + parseAnnotationAliasesConnections(model, getNode("celldesigner:listOfSpeciesAliases", nodes)); + parseAnnotationComplexAliasesConnections(model, getNode("celldesigner:listOfComplexSpeciesAliases", nodes)); + } + + if (listOfGroups != null) { + layerParser.parseGroups(model, listOfGroups); + } + + } + + /** + * Parses celldesigner:listOfComplexSpeciesAliases node for annotation part of + * the CellDEsigner format. + * + * @param model + * model that is parsed + * @param aliasNode + * node to parse + * @throws InvalidXmlSchemaException + * thrown when xml node contains data that is not supported by xml + * schema + */ + void parseAnnotationComplexAliasesConnections(Model model, Node aliasNode) throws InvalidXmlSchemaException { + NodeList nodes = aliasNode.getChildNodes(); + for (int x = 0; x < nodes.getLength(); x++) { + Node node = nodes.item(x); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getNodeName().equalsIgnoreCase("celldesigner:complexSpeciesAlias")) { + String aliasId = getNodeAttr("id", node); + String complexId = getNodeAttr("complexSpeciesAlias", node); + Complex alias = model.getElementByElementId(aliasId); + if (alias == null) { + throw new InvalidXmlSchemaException("Alias does not exist " + aliasId); + } + Complex parentComplex = model.getElementByElementId(complexId); + if (parentComplex != null) { + parentComplex.addSpecies(alias); + alias.setComplex(parentComplex); + } + } else { + throw new InvalidXmlSchemaException( + "Unknown element of celldesigner:listOfComplexSpeciesAliases: " + node.getNodeName()); + } + } + } + + } + + /** + * Parses celldesigner:listOfSpeciesAliases node for annotation part of the + * CellDesigner format. + * + * @param model + * model that is parsed + * @param aliasNode + * node to parse + * @throws InvalidXmlSchemaException + * thrown when xml node contains data that is not supported by xml + * schema + */ + void parseAnnotationAliasesConnections(Model model, Node aliasNode) throws InvalidXmlSchemaException { + NodeList nodes = aliasNode.getChildNodes(); + for (int x = 0; x < nodes.getLength(); x++) { + Node node = nodes.item(x); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getNodeName().equalsIgnoreCase("celldesigner:speciesAlias")) { + String aliasId = getNodeAttr("id", node); + String complexId = getNodeAttr("complexSpeciesAlias", node); + Element alias = model.getElementByElementId(aliasId); + if (alias == null) { + throw new InvalidXmlSchemaException("Alias does not exist " + aliasId); + } else if (alias instanceof Species) { + Species species = ((Species) alias); + Complex complex = model.getElementByElementId(complexId); + if (complex != null) { + species.setComplex(complex); + complex.addSpecies(species); + } + } + } else { + throw new InvalidXmlSchemaException( + "Unknown element of celldesigner:listOfSpeciesAliases: " + node.getNodeName()); + } + } + } + } + + /** + * Transforms model into CellDesigner xml. + * + * @param model + * model that should be transformed + * @return CellDesigner xml string for the model + * @throws InconsistentModelException + * thrown when then model is invalid + */ + public String toXml(Model model) throws InconsistentModelException { + CellDesignerElementCollection elements = new CellDesignerElementCollection(); + + SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); + ReactionCollectionXmlParser reactionCollectionXmlParser = new ReactionCollectionXmlParser(model, elements, false); + aliasCollectionParser = new AliasCollectionXmlParser(elements, model); + + StringBuilder result = new StringBuilder(); + result.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + result.append("<sbml xmlns=\"http://www.sbml.org/sbml/level2/version4\" " + + "xmlns:celldesigner=\"http://www.sbml.org/2001/ns/celldesigner\" level=\"2\" version=\"4\">\n"); + // metaid is a strang cell designer id, usually it's model id and as far as + // we can tell it's not used at all + result.append("<model metaid=\"" + model.getIdModel() + "\" id=\"" + model.getIdModel() + "\">\n"); + + if (model.getNotes() != null) { + result.append("<notes>"); + result.append(escapeXml(model.getNotes())); + result.append("</notes>"); + } + + result.append(annotationToXml(model, elements)); + + compartmentCollectionXmlParser = new CompartmentCollectionXmlParser(elements); + + result.append(compartmentCollectionXmlParser.toXml(model.getCompartments())); + + result.append(speciesCollectionXmlParser.speciesCollectionToSbmlString(model.getSpeciesList())); + + result.append(reactionCollectionXmlParser.reactionCollectionToXmlString(model.getReactions())); + + result.append("</model>"); + result.append("</sbml>"); + return result.toString(); + } + + /** + * Generates xml node that should be in annotation part of the model. + * + * @param model + * model to transform + * @param elements + * collection of {@link CellDesignerElement cell designer elements} + * parsed from xml + * @return annotation xml string for the model + */ + private String annotationToXml(Model model, CellDesignerElementCollection elements) { + SpeciesCollectionXmlParser speciesCollectionXmlParser = new SpeciesCollectionXmlParser(elements); + + StringBuilder result = new StringBuilder(); + result.append("<annotation>\n"); + result.append("<celldesigner:extension>\n"); + result.append("<celldesigner:modelVersion>4.0</celldesigner:modelVersion>\n"); + result.append("<celldesigner:modelDisplay sizeX=\"" + model.getWidth().intValue() + "\" sizeY=\"" + + model.getHeight().intValue() + "\"/>\n"); + + result.append(speciesCollectionXmlParser.speciesCollectionToXmlIncludedString(model.getSpeciesList())); + + result.append(aliasCollectionParser.compartmentAliasCollectionToXmlString(model.getCompartments())); + result.append(aliasCollectionParser.complexAliasCollectionToXmlString(model.getComplexList())); + result.append(aliasCollectionParser.speciesAliasCollectionToXmlString(model.getNotComplexSpeciesList())); + + List<Protein> proteins = new ArrayList<>(); + List<Gene> genes = new ArrayList<>(); + List<Rna> rnas = new ArrayList<>(); + List<AntisenseRna> antisenseRnas = new ArrayList<>(); + for (Element element : model.getElements()) { + if (element instanceof Protein) { + proteins.add((Protein) element); + } else if (element instanceof Gene) { + genes.add((Gene) element); + } else if (element instanceof AntisenseRna) { + antisenseRnas.add((AntisenseRna) element); + } else if (element instanceof Rna) { + rnas.add((Rna) element); + } + } + + result.append(speciesCollectionXmlParser.proteinCollectionToXmlString(proteins)); + result.append(speciesCollectionXmlParser.geneCollectionToXmlString(genes)); + result.append(speciesCollectionXmlParser.rnaCollectionToXmlString(rnas)); + result.append(speciesCollectionXmlParser.antisenseRnaCollectionToXmlString(antisenseRnas)); + result.append(layerParser.layerCollectionToXml(model.getLayers())); + + result.append("</celldesigner:extension>\n"); + result.append("</annotation>\n"); + return result.toString(); + } + + @Override + public InputStream exportModelToInputStream(Model model) throws InconsistentModelException { + String exportedString = toXml(model); + InputStream inputStream = new ByteArrayInputStream(exportedString.getBytes()); + return inputStream; + } + + @Override + public File exportModelToFile(Model model, String filePath) throws InconsistentModelException, IOException { + File file = new File(filePath); + String exportedString = toXml(model); + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(exportedString); + fileWriter.flush(); + fileWriter.close(); + + return file; + } + + @Override + public String getCommonName() { + return "CellDesigner SBML"; + } + + @Override + public MimeType getMimeType() { + return MimeType.SBML; + } + + @Override + public String getFileExtension() { + return "xml"; + } } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionCollectionXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionCollectionXmlParser.java new file mode 100644 index 0000000000..ceeaa4963e --- /dev/null +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionCollectionXmlParser.java @@ -0,0 +1,24 @@ +package lcsb.mapviewer.converter.model.celldesigner.function; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Node; + +import lcsb.mapviewer.common.XmlParser; +import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; +import lcsb.mapviewer.model.map.SbmlFunction; + +public class FunctionCollectionXmlParser extends XmlParser { + + private FunctionXmlParser functionParser = new FunctionXmlParser(); + + public Set<SbmlFunction> parseXmlFunctionCollection(Node functionsNode) throws InvalidXmlSchemaException { + Set<SbmlFunction> result = new HashSet<>(); + for (Node node : super.getNodes("functionDefinition", functionsNode.getChildNodes())) { + result.add(functionParser.parseFunction(node)); + } + return result; + } + +} diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java new file mode 100644 index 0000000000..b25b2829d1 --- /dev/null +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java @@ -0,0 +1,44 @@ +package lcsb.mapviewer.converter.model.celldesigner.function; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Node; + +import lcsb.mapviewer.common.XmlParser; +import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; +import lcsb.mapviewer.model.map.SbmlFunction; + +public class FunctionXmlParser extends XmlParser { + Logger logger = Logger.getLogger(FunctionXmlParser.class); + + public SbmlFunction parseFunction(Node functionNode) throws InvalidXmlSchemaException { + String functionId = getNodeAttr("id", functionNode); + + SbmlFunction result = new SbmlFunction(functionId); + result.setName(getNodeAttr("name", functionNode)); + Node mathDefinition = getNode("math", functionNode); + if (mathDefinition == null) { + throw new InvalidXmlSchemaException("Function " + functionId + " doesn't contain MathML definition (math node)"); + } + result.setDefinition(nodeToString(mathDefinition)); + result.setArguments(parseArgumentsFromMath(mathDefinition, functionId)); + + return result; + } + + private List<String> parseArgumentsFromMath(Node mathDefinition, String functionId) throws InvalidXmlSchemaException { + List<String> result = new ArrayList<>(); + Node lambdaDefinition = getNode("lambda", mathDefinition); + if (lambdaDefinition == null) { + throw new InvalidXmlSchemaException("Function " + functionId + " doesn't contain valid MathML lambda node"); + } + List<Node> variables = super.getNodes("bvar", lambdaDefinition.getChildNodes()); + for (Node node : variables) { + result.add(getNodeValue(getNode("ci", node)).trim()); + } + return result; + } + +} diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java index ac9d237edf..6484b40970 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java @@ -36,342 +36,358 @@ import lcsb.mapviewer.model.map.species.field.ModificationState; import lcsb.mapviewer.modelutils.map.ElementUtils; public class ComplexParserTests extends CellDesignerTestFunctions { - Logger logger = Logger.getLogger(ComplexParserTests.class); - - ElementUtils eu = new ElementUtils(); - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testParseCompartmens() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/reactions/centeredAnchorInModifier.xml"); - - assertEquals(0, model.getCompartments().size()); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testParseBubbles() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/bubbles.xml"); - - Element species = model.getElementByElementId("sa6"); - assertNotNull(species); - Protein protein = (Protein) species; - assertTrue(protein.getModificationResidues().size() > 0); - assertNotNull(protein.getStructuralState()); - assertFalse(protein.getStructuralState().equals("")); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testParseCompartmensRelation() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/problematic/elements_in_compartments.xml"); - - List<Element> aliases = new ArrayList<>(); - aliases.add(model.getElementByElementId("csa3")); - aliases.add(model.getElementByElementId("csa4")); - aliases.add(model.getElementByElementId("csa5")); - aliases.add(model.getElementByElementId("csa6")); - aliases.add(model.getElementByElementId("sa3")); - aliases.add(model.getElementByElementId("sa5")); - aliases.add(model.getElementByElementId("sa6")); - aliases.add(model.getElementByElementId("sa7")); - aliases.add(model.getElementByElementId("sa8")); - aliases.add(model.getElementByElementId("sa9")); - aliases.add(model.getElementByElementId("sa10")); - aliases.add(model.getElementByElementId("sa11")); - aliases.add(model.getElementByElementId("sa12")); - aliases.add(model.getElementByElementId("sa13")); - aliases.add(model.getElementByElementId("sa14")); - aliases.add(model.getElementByElementId("sa15")); - aliases.add(model.getElementByElementId("sa16")); - aliases.add(model.getElementByElementId("sa17")); - aliases.add(model.getElementByElementId("sa18")); - aliases.add(model.getElementByElementId("sa19")); - aliases.add(model.getElementByElementId("sa20")); - for (Element alias : aliases) { - assertNotNull(eu.getElementTag(alias) + " does not contain info about compartment", alias.getCompartment()); - } - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testParseProteins() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/problematic/acetyled_protein.xml"); - - Set<ModificationState> residues = new HashSet<ModificationState>(); - for (Element element : model.getElements()) { - if (element instanceof Species) { - Protein p = (Protein) element; - for (ModificationResidue mr : p.getModificationResidues()) { - residues.add(mr.getState()); - } - } - } - // we have a protein which is acetylated and not acetylated so two types - // of residues - assertEquals(2, residues.size()); - - assertEquals(ModificationState.ACETYLATED, ((Protein) model.getElementByElementId("sa2")).getModificationResidues().get(0).getState()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testNotesComplexesInNested() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/includedSpecies.xml"); - Element species = model.getElementByElementId("sa1"); - assertNotNull(species); - assertNotNull(species.getNotes()); - assertTrue("Wrong notes: " + species.getNotes(), species.getNotes().contains("hello world")); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testHypotheticalComplex() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/problematic/hypothetical_complex.xml"); - Complex species = (Complex) model.getElementByElementId("csa1"); - assertTrue(species.isHypothetical()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testProblematicAcetylation() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/problematic/problematic_acetylation.xml"); - Protein p1 = (Protein) model.getElementByElementId("sa73"); - Protein p2 = (Protein) model.getElementByElementId("sa27"); - assertEquals(ModificationState.ACETYLATED, p1.getModificationResidues().get(0).getState()); - assertFalse(ModificationState.ACETYLATED.equals(p2.getModificationResidues().get(0).getState())); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testDuplicateMiriam() throws Exception { - Model model; - try { - model = getModelForFile("testFiles/problematic/duplicated_miriam.xml"); - Protein p1 = (Protein) model.getElementByElementId("sa1"); - Set<String> ids = new HashSet<>(); - - assertTrue(p1.getMiriamData().size() > 0); - for (MiriamData md : p1.getMiriamData()) { - if (md.getDataType().equals(MiriamType.PUBMED)) { - assertFalse("Protein contains double pubmed annotation for pubmed id: " + md.getResource(), ids.contains(md.getResource())); - ids.add(md.getResource()); - } - } - assertTrue(ids.size() > 0); - assertEquals(2, getWarnings().size()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testKappaInDescription() throws Exception { - try { - Model model = getModelForFile("testFiles/problematic/kappa_example.xml"); - - Element species = model.getElementByElementId("sa1"); - - assertFalse(species.getName().toLowerCase().contains("kappa")); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testMissingXmlNodes() throws Exception { - try { - Model model = getModelForFile("testFiles/missing_xml_nodes.xml"); - - assertTrue(((Species) model.getElementByElementId("sa3")).isHypothetical()); - assertTrue(((Species) model.getElementByElementId("sa4")).isHypothetical()); - assertTrue(((Species) model.getElementByElementId("sa5")).isHypothetical()); - - assertFalse(((Species) model.getElementByElementId("sa12")).isHypothetical()); - assertFalse(((Species) model.getElementByElementId("sa13")).isHypothetical()); - assertFalse(((Species) model.getElementByElementId("sa14")).isHypothetical()); - assertFalse(((Species) model.getElementByElementId("sa15")).isHypothetical()); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testParsingSpecialCharactersInName() throws Exception { - try { - Model model = new ModelFullIndexed(null); - model.setIdModel("as"); - model.setWidth(100); - model.setHeight(100); - GenericProtein alias = new GenericProtein("aid"); - alias.setName("name & no-name"); - model.addElement(alias); - - CellDesignerXmlParser parser = new CellDesignerXmlParser(); - String string = parser.toXml(model); - - InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); - - ConverterParams params = new ConverterParams().inputStream(stream).sizeAutoAdjust(false); - - Model model2 = parser.createModel(params); - - ModelComparator comparator = new ModelComparator(); - - assertEquals(0, comparator.compare(model, model2)); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testParsingEndLineInName() throws Exception { - try { - Model model = new ModelFullIndexed(null); - model.setIdModel("as"); - model.setWidth(100); - model.setHeight(100); - GenericProtein alias = new GenericProtein("aid"); - alias.setName("name\rno-name"); - model.addElement(alias); - - CellDesignerXmlParser parser = new CellDesignerXmlParser(); - String string = parser.toXml(model); - - InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); - - ConverterParams params = new ConverterParams().inputStream(stream).sizeAutoAdjust(false); - - Model model2 = parser.createModel(params); - - ModelComparator comparator = new ModelComparator(); - - assertEquals(0, comparator.compare(model, model2)); - - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testWarningInParser() throws Exception { - try { - getModelForFile("testFiles/problematic/invalid_elements_name.xml"); - assertTrue(getWarnings().size() > 0); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testRnaWithRegion() throws Exception { - try { - Model model = getModelForFile("testFiles/rnaWithRegion.xml"); - for (Element species : model.getNotComplexSpeciesList()) { - Rna rna = (Rna) species; - assertEquals(1, rna.getRegions().size()); - } - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testProtinWithModifications() throws Exception { - try { - Model model = getModelForFile("testFiles/proteinWithEverPossibleModification.xml"); - Protein protein = (Protein) model.getElementByElementId("sa1"); - assertEquals(14, protein.getModificationResidues().size()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testAntisenseRnaWithRegion() throws Exception { - try { - Model model = getModelForFile("testFiles/antisenseRnaWithRegion.xml"); - for (Species species : model.getNotComplexSpeciesList()) { - AntisenseRna rna = (AntisenseRna) species; - assertEquals(1, rna.getRegions().size()); - } - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - - @Test - public void testPhosporylatedProteinToXml() throws Exception { - try { - Model model = getModelForFile("testFiles/problematic/phosphorylated_protein.xml"); - model.setName(null); - CellDesignerXmlParser p = new CellDesignerXmlParser(); - String xml = p.toXml(model); - InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); - Model model2 = p.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false)); - ModelComparator comparator = new ModelComparator(); - assertEquals(0, comparator.compare(model, model2)); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } + Logger logger = Logger.getLogger(ComplexParserTests.class); + + ElementUtils eu = new ElementUtils(); + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParseFunctions() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/function.xml"); + + assertEquals(1, model.getFunctions().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParseCompartmens() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/reactions/centeredAnchorInModifier.xml"); + + assertEquals(0, model.getCompartments().size()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParseBubbles() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/bubbles.xml"); + + Element species = model.getElementByElementId("sa6"); + assertNotNull(species); + Protein protein = (Protein) species; + assertTrue(protein.getModificationResidues().size() > 0); + assertNotNull(protein.getStructuralState()); + assertFalse(protein.getStructuralState().equals("")); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParseCompartmensRelation() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/problematic/elements_in_compartments.xml"); + + List<Element> aliases = new ArrayList<>(); + aliases.add(model.getElementByElementId("csa3")); + aliases.add(model.getElementByElementId("csa4")); + aliases.add(model.getElementByElementId("csa5")); + aliases.add(model.getElementByElementId("csa6")); + aliases.add(model.getElementByElementId("sa3")); + aliases.add(model.getElementByElementId("sa5")); + aliases.add(model.getElementByElementId("sa6")); + aliases.add(model.getElementByElementId("sa7")); + aliases.add(model.getElementByElementId("sa8")); + aliases.add(model.getElementByElementId("sa9")); + aliases.add(model.getElementByElementId("sa10")); + aliases.add(model.getElementByElementId("sa11")); + aliases.add(model.getElementByElementId("sa12")); + aliases.add(model.getElementByElementId("sa13")); + aliases.add(model.getElementByElementId("sa14")); + aliases.add(model.getElementByElementId("sa15")); + aliases.add(model.getElementByElementId("sa16")); + aliases.add(model.getElementByElementId("sa17")); + aliases.add(model.getElementByElementId("sa18")); + aliases.add(model.getElementByElementId("sa19")); + aliases.add(model.getElementByElementId("sa20")); + for (Element alias : aliases) { + assertNotNull(eu.getElementTag(alias) + " does not contain info about compartment", alias.getCompartment()); + } + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParseProteins() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/problematic/acetyled_protein.xml"); + + Set<ModificationState> residues = new HashSet<ModificationState>(); + for (Element element : model.getElements()) { + if (element instanceof Species) { + Protein p = (Protein) element; + for (ModificationResidue mr : p.getModificationResidues()) { + residues.add(mr.getState()); + } + } + } + // we have a protein which is acetylated and not acetylated so two types + // of residues + assertEquals(2, residues.size()); + + assertEquals(ModificationState.ACETYLATED, + ((Protein) model.getElementByElementId("sa2")).getModificationResidues().get(0).getState()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testNotesComplexesInNested() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/includedSpecies.xml"); + Element species = model.getElementByElementId("sa1"); + assertNotNull(species); + assertNotNull(species.getNotes()); + assertTrue("Wrong notes: " + species.getNotes(), species.getNotes().contains("hello world")); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testHypotheticalComplex() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/problematic/hypothetical_complex.xml"); + Complex species = (Complex) model.getElementByElementId("csa1"); + assertTrue(species.isHypothetical()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testProblematicAcetylation() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/problematic/problematic_acetylation.xml"); + Protein p1 = (Protein) model.getElementByElementId("sa73"); + Protein p2 = (Protein) model.getElementByElementId("sa27"); + assertEquals(ModificationState.ACETYLATED, p1.getModificationResidues().get(0).getState()); + assertFalse(ModificationState.ACETYLATED.equals(p2.getModificationResidues().get(0).getState())); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testDuplicateMiriam() throws Exception { + Model model; + try { + model = getModelForFile("testFiles/problematic/duplicated_miriam.xml"); + Protein p1 = (Protein) model.getElementByElementId("sa1"); + Set<String> ids = new HashSet<>(); + + assertTrue(p1.getMiriamData().size() > 0); + for (MiriamData md : p1.getMiriamData()) { + if (md.getDataType().equals(MiriamType.PUBMED)) { + assertFalse("Protein contains double pubmed annotation for pubmed id: " + md.getResource(), + ids.contains(md.getResource())); + ids.add(md.getResource()); + } + } + assertTrue(ids.size() > 0); + assertEquals(2, getWarnings().size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testKappaInDescription() throws Exception { + try { + Model model = getModelForFile("testFiles/problematic/kappa_example.xml"); + + Element species = model.getElementByElementId("sa1"); + + assertFalse(species.getName().toLowerCase().contains("kappa")); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testMissingXmlNodes() throws Exception { + try { + Model model = getModelForFile("testFiles/missing_xml_nodes.xml"); + + assertTrue(((Species) model.getElementByElementId("sa3")).isHypothetical()); + assertTrue(((Species) model.getElementByElementId("sa4")).isHypothetical()); + assertTrue(((Species) model.getElementByElementId("sa5")).isHypothetical()); + + assertFalse(((Species) model.getElementByElementId("sa12")).isHypothetical()); + assertFalse(((Species) model.getElementByElementId("sa13")).isHypothetical()); + assertFalse(((Species) model.getElementByElementId("sa14")).isHypothetical()); + assertFalse(((Species) model.getElementByElementId("sa15")).isHypothetical()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParsingSpecialCharactersInName() throws Exception { + try { + Model model = new ModelFullIndexed(null); + model.setIdModel("as"); + model.setWidth(100); + model.setHeight(100); + GenericProtein alias = new GenericProtein("aid"); + alias.setName("name & no-name"); + model.addElement(alias); + + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + String string = parser.toXml(model); + + InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); + + ConverterParams params = new ConverterParams().inputStream(stream).sizeAutoAdjust(false); + + Model model2 = parser.createModel(params); + + ModelComparator comparator = new ModelComparator(); + + assertEquals(0, comparator.compare(model, model2)); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testParsingEndLineInName() throws Exception { + try { + Model model = new ModelFullIndexed(null); + model.setIdModel("as"); + model.setWidth(100); + model.setHeight(100); + GenericProtein alias = new GenericProtein("aid"); + alias.setName("name\rno-name"); + model.addElement(alias); + + CellDesignerXmlParser parser = new CellDesignerXmlParser(); + String string = parser.toXml(model); + + InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); + + ConverterParams params = new ConverterParams().inputStream(stream).sizeAutoAdjust(false); + + Model model2 = parser.createModel(params); + + ModelComparator comparator = new ModelComparator(); + + assertEquals(0, comparator.compare(model, model2)); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testWarningInParser() throws Exception { + try { + getModelForFile("testFiles/problematic/invalid_elements_name.xml"); + assertTrue(getWarnings().size() > 0); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testRnaWithRegion() throws Exception { + try { + Model model = getModelForFile("testFiles/rnaWithRegion.xml"); + for (Element species : model.getNotComplexSpeciesList()) { + Rna rna = (Rna) species; + assertEquals(1, rna.getRegions().size()); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testProtinWithModifications() throws Exception { + try { + Model model = getModelForFile("testFiles/proteinWithEverPossibleModification.xml"); + Protein protein = (Protein) model.getElementByElementId("sa1"); + assertEquals(14, protein.getModificationResidues().size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testAntisenseRnaWithRegion() throws Exception { + try { + Model model = getModelForFile("testFiles/antisenseRnaWithRegion.xml"); + for (Species species : model.getNotComplexSpeciesList()) { + AntisenseRna rna = (AntisenseRna) species; + assertEquals(1, rna.getRegions().size()); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Test + public void testPhosporylatedProteinToXml() throws Exception { + try { + Model model = getModelForFile("testFiles/problematic/phosphorylated_protein.xml"); + model.setName(null); + CellDesignerXmlParser p = new CellDesignerXmlParser(); + String xml = p.toXml(model); + InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + Model model2 = p.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false)); + ModelComparator comparator = new ModelComparator(); + assertEquals(0, comparator.compare(model, model2)); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } } diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParserTest.java new file mode 100644 index 0000000000..71af481a35 --- /dev/null +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParserTest.java @@ -0,0 +1,49 @@ +package lcsb.mapviewer.converter.model.celldesigner.function; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.Test; + +import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; +import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions; +import lcsb.mapviewer.model.map.SbmlFunction; + +public class FunctionXmlParserTest extends CellDesignerTestFunctions { + + FunctionXmlParser parser = new FunctionXmlParser(); + + @Test + public void testParseBasicData() throws InvalidXmlSchemaException, IOException { + SbmlFunction fun = parser + .parseFunction(super.getXmlDocumentFromFile("testFiles/function/simple.xml").getFirstChild()); + assertNotNull(fun); + assertEquals(fun.getFunctionId(), "function_id"); + assertEquals(fun.getName(), "Function name"); + assertTrue(fun.getDefinition().indexOf("lambda") >= 0); + assertTrue(fun.getDefinition().indexOf("apply") >= 0); + } + + @Test + public void testParseArgumentsData() throws InvalidXmlSchemaException, IOException { + SbmlFunction fun = parser + .parseFunction(super.getXmlDocumentFromFile("testFiles/function/simple.xml").getFirstChild()); + assertNotNull(fun); + assertEquals(fun.getArguments().size(), 2); + assertEquals(fun.getArguments().get(0), "x"); + } + + @Test(expected = InvalidXmlSchemaException.class) + public void testParseInvalidDefinition() throws InvalidXmlSchemaException, IOException { + parser.parseFunction(super.getXmlDocumentFromFile("testFiles/function/invalid_definition.xml").getFirstChild()); + } + + @Test(expected = InvalidXmlSchemaException.class) + public void testParseInvalidMathMLNode() throws InvalidXmlSchemaException, IOException { + parser.parseFunction(super.getXmlDocumentFromFile("testFiles/function/invalid_math.xml").getFirstChild()); + } + +} diff --git a/converter-CellDesigner/testFiles/function.xml b/converter-CellDesigner/testFiles/function.xml new file mode 100644 index 0000000000..acdb36ed9a --- /dev/null +++ b/converter-CellDesigner/testFiles/function.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4"> +<model metaid="untitled" id="untitled"> +<annotation> +<celldesigner:extension> +<celldesigner:modelVersion>4.0</celldesigner:modelVersion> +<celldesigner:modelDisplay sizeX="600" sizeY="400"/> +<celldesigner:listOfCompartmentAliases/> +<celldesigner:listOfComplexSpeciesAliases/> +<celldesigner:listOfSpeciesAliases/> +<celldesigner:listOfGroups/> +<celldesigner:listOfProteins/> +<celldesigner:listOfGenes/> +<celldesigner:listOfRNAs/> +<celldesigner:listOfAntisenseRNAs/> +<celldesigner:listOfLayers/> +<celldesigner:listOfBlockDiagrams/> +</celldesigner:extension> +</annotation> +<listOfFunctionDefinitions> +<functionDefinition metaid="function_id" id="function_id" name="Function name"> +<math xmlns="http://www.w3.org/1998/Math/MathML"> +<lambda> +<bvar> +<ci> x </ci> +</bvar> +<bvar> +<ci> y </ci> +</bvar> +<apply> +<plus/> +<ci> x </ci> +<ci> y </ci> +</apply> +</lambda> +</math> +</functionDefinition> +</listOfFunctionDefinitions> +<listOfUnitDefinitions> +<unitDefinition metaid="substance" id="substance" name="substance"> +<listOfUnits> +<unit metaid="CDMT00004" kind="mole"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="volume" id="volume" name="volume"> +<listOfUnits> +<unit metaid="CDMT00005" kind="litre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="area" id="area" name="area"> +<listOfUnits> +<unit metaid="CDMT00006" kind="metre" exponent="2"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="length" id="length" name="length"> +<listOfUnits> +<unit metaid="CDMT00007" kind="metre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="time" id="time" name="time"> +<listOfUnits> +<unit metaid="CDMT00008" kind="second"/> +</listOfUnits> +</unitDefinition> +</listOfUnitDefinitions> +<listOfCompartments> +<compartment metaid="default" id="default" size="1" units="volume"/> +</listOfCompartments> +</model> +</sbml> diff --git a/converter-CellDesigner/testFiles/function/invalid_definition.xml b/converter-CellDesigner/testFiles/function/invalid_definition.xml new file mode 100644 index 0000000000..185faad8a7 --- /dev/null +++ b/converter-CellDesigner/testFiles/function/invalid_definition.xml @@ -0,0 +1,2 @@ +<functionDefinition metaid="function_id" id="function_id" name="Function name"> +</functionDefinition> diff --git a/converter-CellDesigner/testFiles/function/invalid_math.xml b/converter-CellDesigner/testFiles/function/invalid_math.xml new file mode 100644 index 0000000000..81df2b0f89 --- /dev/null +++ b/converter-CellDesigner/testFiles/function/invalid_math.xml @@ -0,0 +1,4 @@ +<functionDefinition metaid="function_id" id="function_id" name="Function name"> +<math xmlns="http://www.w3.org/1998/Math/MathML"> +</math> +</functionDefinition> diff --git a/converter-CellDesigner/testFiles/function/simple.xml b/converter-CellDesigner/testFiles/function/simple.xml new file mode 100644 index 0000000000..8f43b43daa --- /dev/null +++ b/converter-CellDesigner/testFiles/function/simple.xml @@ -0,0 +1,17 @@ +<functionDefinition metaid="function_id" id="function_id" name="Function name"> +<math xmlns="http://www.w3.org/1998/Math/MathML"> +<lambda> +<bvar> +<ci> x </ci> +</bvar> +<bvar> +<ci> y </ci> +</bvar> +<apply> +<plus/> +<ci> x </ci> +<ci> y </ci> +</apply> +</lambda> +</math> +</functionDefinition> -- GitLab