diff --git a/vcell-core/src/main/java/org/jlibsedml/Model.java b/vcell-core/src/main/java/org/jlibsedml/Model.java
index 5172caa9bb..b5d8392e2f 100644
--- a/vcell-core/src/main/java/org/jlibsedml/Model.java
+++ b/vcell-core/src/main/java/org/jlibsedml/Model.java
@@ -8,6 +8,8 @@
import org.jlibsedml.modelsupport.SUPPORTED_LANGUAGE;
+import static org.jlibsedml.execution.ArchiveModelResolver.SPACE_URI_ESCAPE_SEQUENCE;
+
/**
* Encapsulates a SED-ML Model element. Note that this object is not the
* computational model itself, but holds information about the model within
@@ -19,7 +21,7 @@
public final class Model extends AbstractIdentifiableElement {
private String language = null;
- private String source = null;
+ private final String source_path_or_URI_string;
/**
* Sets the model language that this element refers to. This should ideally be a URN,
@@ -45,21 +47,21 @@ public void setLanguage(String language) {
* This should ideally be a URN, which may already be defined in
* {@link SUPPORTED_LANGUAGE}. If no language describes this
* model, the argument may be null
.
- * @param source
- * A mandatory URI to the model source.
+ * @param source_path_or_URI_string
+ * A mandatory URI or local path to the model source.
* @throws IllegalArgumentException
* if any argument except name
is null or an empty
* string.
*/
- public Model(String id, String name, String language, String source) {
+ public Model(String id, String name, String language, String source_path_or_URI_string) {
super(id, name);
if (SEDMLElementFactory.getInstance().isStrictCreation()) {
- Assert.checkNoNullArgs(source);
- Assert.stringsNotEmpty(source);
+ Assert.checkNoNullArgs(source_path_or_URI_string);
+ Assert.stringsNotEmpty(source_path_or_URI_string);
}
this.language = language;
- this.source = source;
+ this.source_path_or_URI_string = source_path_or_URI_string;
}
/**
@@ -76,7 +78,7 @@ public Model(String id, String name, String language, String source) {
* if any argument is null
*/
public Model(Model toCopy, String id) {
- this(id, toCopy.getName(), toCopy.getLanguage(), toCopy.getSource());
+ this(id, toCopy.getName(), toCopy.getLanguage(), toCopy.getSourcePathOrURIString());
}
/**
@@ -139,9 +141,8 @@ public String getLanguage() {
*
* @return A String
*/
- public String getSource() {
-
- return source;
+ public String getSourcePathOrURIString() {
+ return this.source_path_or_URI_string;
}
/**
@@ -231,9 +232,7 @@ public String getSource() {
* cannot be converted to a URI.
*/
public URI getSourceURI() throws URISyntaxException {
-
- return new URI(source);
-
+ return new URI(this.source_path_or_URI_string.replace(" ", SPACE_URI_ESCAPE_SEQUENCE));
}
/**
@@ -269,23 +268,13 @@ public boolean isSourceURIRelative() {
*/
public boolean isSourceValidURI() {
try {
- new URI(getSource());
+ getSourceURI();
} catch (URISyntaxException e) {
return false;
}
return true;
}
- /**
- *
- * @param srcString
- * A URI of where this model can be retrieved.
- * Attention: if the string is a model reference, it should be prefixed with "#"
- */
- public void setSource(String srcString) {
- source = srcString;
- }
-
/**
* @see Object#toString()
*/
@@ -293,7 +282,7 @@ public String toString() {
return new StringBuffer().append("Model [").append("id=").append(
getId()).append(", ").append("name=").append(getName())
.append(", ").append("language=").append(language).append(
- ", ").append("src=").append(source).append("]").toString();
+ ", ").append("src=").append(this.source_path_or_URI_string).append("]").toString();
}
@Override
@@ -311,6 +300,5 @@ public boolean accept(SEDMLVisitor visitor){
}
}
return true;
-
}
}
diff --git a/vcell-core/src/main/java/org/jlibsedml/SEDMLWriter.java b/vcell-core/src/main/java/org/jlibsedml/SEDMLWriter.java
index 09fcb126c9..46cee96f0e 100644
--- a/vcell-core/src/main/java/org/jlibsedml/SEDMLWriter.java
+++ b/vcell-core/src/main/java/org/jlibsedml/SEDMLWriter.java
@@ -119,7 +119,7 @@ Element getXML(Model sedmlModel) {
node.setAttribute(SEDMLTags.MODEL_ATTR_LANGUAGE, s); // insert
// 'type'
// attribute
- s = sedmlModel.getSource();
+ s = sedmlModel.getSourcePathOrURIString();
if (s != null)
node.setAttribute(SEDMLTags.MODEL_ATTR_SOURCE, s); // insert
// 'source'
diff --git a/vcell-core/src/main/java/org/jlibsedml/SedML.java b/vcell-core/src/main/java/org/jlibsedml/SedML.java
index d0f592fe92..debdb8b795 100644
--- a/vcell-core/src/main/java/org/jlibsedml/SedML.java
+++ b/vcell-core/src/main/java/org/jlibsedml/SedML.java
@@ -733,7 +733,7 @@ public final boolean addIdentifiersAsDataGenerators(AbstractTask task,
public List getBaseModels() {
Set set = new HashSet();
for (Model m : getModels()) {
- if (getModelWithId(m.getSource()) == null) {
+ if (getModelWithId(m.getSourcePathOrURIString()) == null) {
set.add(m);
}
}
diff --git a/vcell-core/src/main/java/org/jlibsedml/execution/ArchiveModelResolver.java b/vcell-core/src/main/java/org/jlibsedml/execution/ArchiveModelResolver.java
index 4d3320a65b..2dc3bb76a1 100644
--- a/vcell-core/src/main/java/org/jlibsedml/execution/ArchiveModelResolver.java
+++ b/vcell-core/src/main/java/org/jlibsedml/execution/ArchiveModelResolver.java
@@ -10,6 +10,8 @@
import org.jlibsedml.IModelContent;
public class ArchiveModelResolver implements IModelResolver {
+ public final static String SPACE_URI_ESCAPE_SEQUENCE = "%20";
+
private ArchiveComponents ac;
private String sedmlPath = "";
public ArchiveModelResolver(ArchiveComponents ac) {
@@ -17,7 +19,7 @@ public ArchiveModelResolver(ArchiveComponents ac) {
}
public String getModelXMLFor(URI modelURI) {
List children = ac.getModelFiles();
- String modelStr = modelURI.toString();
+ String modelStr = modelURI.toString().replace(SPACE_URI_ESCAPE_SEQUENCE, " ");
// try direct match first
for (IModelContent imc: children) {
String modelElementStr = imc.getName();
diff --git a/vcell-core/src/main/java/org/jlibsedml/execution/ModelResolver.java b/vcell-core/src/main/java/org/jlibsedml/execution/ModelResolver.java
index a98470e07a..8b61dd2621 100644
--- a/vcell-core/src/main/java/org/jlibsedml/execution/ModelResolver.java
+++ b/vcell-core/src/main/java/org/jlibsedml/execution/ModelResolver.java
@@ -121,7 +121,7 @@ public String getModelString(Model m) {
srcURI = sedml.getModelWithId(modelRef).getSourceURI();
// If we need to recurse to the next level:
modelRef = sedml.getModelWithId(modelRef.startsWith("#") ?
- modelRef.substring(1): modelRef).getSource();
+ modelRef.substring(1): modelRef).getSourcePathOrURIString();
} while (srcURI != null && srcURI.toString().contains("#"));
} catch (URISyntaxException e) {
logger.error(MODEL_SRC_NOT_VALID_URI+": "+e.getMessage(), e);
@@ -187,7 +187,7 @@ final String getBaseModel(URI modelSrc) {
}
void getModelModificationTree(Model m, List modelRefs2) {
- String modelSrcRef = m.getSource();
+ String modelSrcRef = m.getSourcePathOrURIString();
modelRefs2.add(m.getId());
if (sedml.getModelWithId(modelSrcRef) != null) {
diff --git a/vcell-core/src/main/java/org/jlibsedml/validation/ModelCyclesDetector.java b/vcell-core/src/main/java/org/jlibsedml/validation/ModelCyclesDetector.java
index 74669cd71e..782da6e126 100644
--- a/vcell-core/src/main/java/org/jlibsedml/validation/ModelCyclesDetector.java
+++ b/vcell-core/src/main/java/org/jlibsedml/validation/ModelCyclesDetector.java
@@ -39,7 +39,7 @@ public List validate() throws XMLException {
List errs = new ArrayList();
List models = sedml.getModels();
for (Model model : models) {
- String src = model.getSource();
+ String src = model.getSourcePathOrURIString();
String id = model.getId();
Set ids = new HashSet();
ids.add(id);
@@ -50,12 +50,12 @@ public List validate() throws XMLException {
errs.add(new SedMLError(line,
"Cycles detected in source references for model "
+ newID + " and "
- + sedml.getModelWithId(newID).getSource(),
+ + sedml.getModelWithId(newID).getSourcePathOrURIString(),
ERROR_SEVERITY.ERROR));
return errs;
} else {
ids.add(newID);
- src = sedml.getModelWithId(src).getSource();
+ src = sedml.getModelWithId(src).getSourcePathOrURIString();
}
}
}
diff --git a/vcell-core/src/main/java/org/jlibsedml/validation/URIValidator.java b/vcell-core/src/main/java/org/jlibsedml/validation/URIValidator.java
index 2e1cdbf128..2c5d186d68 100644
--- a/vcell-core/src/main/java/org/jlibsedml/validation/URIValidator.java
+++ b/vcell-core/src/main/java/org/jlibsedml/validation/URIValidator.java
@@ -30,9 +30,9 @@ public List validate() {
for (Model model: models){
try {
- URI uri = new URI(model.getSource());
+ URI uri = model.getSourceURI();
} catch (URISyntaxException e) {
- errs.add(new SedMLError(0,"ErrMessageRoot[" + model.getSource() +"]", ERROR_SEVERITY.WARNING ));
+ errs.add(new SedMLError(0,"ErrMessageRoot[" + model.getSourcePathOrURIString() +"]", ERROR_SEVERITY.WARNING ));
}
diff --git a/vcell-core/src/main/java/org/vcell/sedml/SEDMLImporter.java b/vcell-core/src/main/java/org/vcell/sedml/SEDMLImporter.java
index e25b734f66..b007a8d7ff 100644
--- a/vcell-core/src/main/java/org/vcell/sedml/SEDMLImporter.java
+++ b/vcell-core/src/main/java/org/vcell/sedml/SEDMLImporter.java
@@ -807,7 +807,7 @@ private Map createBioModels(List models) throws SEDMLIm
// Group models by type for processing order
for (Model model : models){
- if (model.getSource().startsWith("#")){
+ if (model.getSourcePathOrURIString().startsWith("#")){
advancedModelsList.get(ADVANCED_MODEL_TYPES.REFERENCING_MODELS.ordinal()).add(model);
} else if (!model.getListOfChanges().isEmpty()) {
advancedModelsList.get(ADVANCED_MODEL_TYPES.CHANGED_MODELS.ordinal()).add(model);
@@ -866,13 +866,13 @@ private Map createBioModels(List models) throws SEDMLIm
}
private String getReferenceId(Model model){
- String referenceId = model.getSource();
+ String referenceId = model.getSourcePathOrURIString();
return referenceId.startsWith("#") ? referenceId.substring(1) : referenceId;
}
private BioModel getModelReference(String referenceId, Model model, Map idToBiomodelMap) throws SEDMLImportException {
// Were we given a reference ID? We need to check if the parent was processed yet.
- if (referenceId != null && !model.getSource().equals(referenceId)){
+ if (referenceId != null && !model.getSourcePathOrURIString().equals(referenceId)){
boolean canTranslate;
BioModel parentBiomodel = idToBiomodelMap.get(referenceId);
diff --git a/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java b/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java
index fbebad4ca7..8fc9d7c1b9 100644
--- a/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java
+++ b/vcell-math/src/main/java/cbit/vcell/parser/ExpressionMathMLParser.java
@@ -141,6 +141,27 @@ private SimpleNode getRootNode(Element nodeMathML, String timeSymbol) throws Exp
vcellOperationNode = new ASTAndNode();
} else if (operation.getName().equals(MathMLTags.OR)){
vcellOperationNode = new ASTOrNode();
+ } else if (operation.getName().equals(MathMLTags.XOR)){
+ // XOR(A,B) --> OR(AND(A,NOT(B)),AND(NOT(A),B))
+ // NOT(B)
+ ASTNotNode notNode = new ASTNotNode();
+ notNode.jjtAddChild(getRootNode((Element)children.get(2), timeSymbol));
+ // AND(A,NOT(B))
+ ASTAndNode andNode1 = new ASTAndNode();
+ andNode1.jjtAddChild(getRootNode((Element)children.get(1), timeSymbol));
+ andNode1.jjtAddChild(notNode);
+ // NOT(A)
+ ASTNotNode notNode2 = new ASTNotNode();
+ notNode2.jjtAddChild(getRootNode((Element)children.get(1), timeSymbol));
+ // AND(NOT(A),B)
+ ASTAndNode andNode2 = new ASTAndNode();
+ andNode2.jjtAddChild(notNode2);
+ andNode2.jjtAddChild(getRootNode((Element)children.get(2), timeSymbol));
+ // OR(AND(A,NOT(B)),AND(NOT(A),B))
+ ASTOrNode orNode = new ASTOrNode();
+ orNode.jjtAddChild(andNode1);
+ orNode.jjtAddChild(andNode2);
+ return orNode;
} else if (operation.getName().equals(MathMLTags.NOT)){
vcellOperationNode = new ASTNotNode();
} else if (operation.getName().equals(MathMLTags.PLUS)){
diff --git a/vcell-math/src/test/java/cbit/vcell/parser/MathMLTester.java b/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java
similarity index 80%
rename from vcell-math/src/test/java/cbit/vcell/parser/MathMLTester.java
rename to vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java
index 4c89b6f371..1c28811272 100644
--- a/vcell-math/src/test/java/cbit/vcell/parser/MathMLTester.java
+++ b/vcell-math/src/test/java/cbit/vcell/parser/MathMLTest.java
@@ -14,6 +14,7 @@
import org.jmathml.ASTNode;
import org.jmathml.MathMLReader;
import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -25,13 +26,7 @@
import static org.junit.jupiter.api.Assertions.fail;
@Tag("Fast")
-public class MathMLTester {
-
- private Expression expression;
-
- public MathMLTester(Expression exp) {
- this.expression = exp;
- }
+public class MathMLTest {
public static Collection testCases() throws ExpressionException {
int depthOfExpressionTree = 2;
@@ -72,9 +67,23 @@ public static Collection testCases() throws ExpressionException {
return expressions;
}
+ @Test
+ public void testMathMLParsing_XOR() throws IOException, ExpressionException {
+ // XOR is supported as an SBML operator for importing only
+ Expression exp = new Expression("(x && !y) || (!x && y)");
+ String temp_mathMLStr_with_and = ExpressionMathMLPrinter.getMathML(new Expression("x && y"), true,
+ ExpressionMathMLPrinter.MathType.REAL, ExpressionMathMLPrinter.Dialect.SBML_SUBSET);
+ String mathMLStr_with_xor = temp_mathMLStr_with_and.replace("and", "xor");
+ Expression xor_from_MathML = new ExpressionMathMLParser(null).fromMathML(mathMLStr_with_xor, "t");
+ boolean equiv = ExpressionUtils.functionallyEquivalent(exp, xor_from_MathML, true);
+ String msg = "not equivalent: origExp='"+exp.infix()+"', expMathML='"+xor_from_MathML.infix()+"'";
+ assertTrue(equiv, msg);
+ }
+
+
@ParameterizedTest
@MethodSource("testCases")
- public void testMathML_SBMLSubset() throws IOException, ExpressionException {
+ public void testMathML_SBMLSubset(Expression expression) throws IOException, ExpressionException {
if (expression.infix().contains("atan")){
return;
}
@@ -88,7 +97,7 @@ public void testMathML_SBMLSubset() throws IOException, ExpressionException {
@ParameterizedTest
@MethodSource("testCases")
- public void test_vcell_mathml_jMathML_mathml_vcell() throws IOException, ExpressionException {
+ public void test_vcell_mathml_jMathML_mathml_vcell(Expression expression) throws IOException, ExpressionException {
List tokensToAvoid = Arrays.asList(
"atan",
"sech", "csch", "coth",
@@ -119,7 +128,7 @@ public void test_vcell_mathml_jMathML_mathml_vcell() throws IOException, Express
@ParameterizedTest
@MethodSource("testCases")
- public void testMathML_GeneralSubset() throws IOException, ExpressionException {
+ public void testMathML_GeneralSubset(Expression expression) throws IOException, ExpressionException {
if (expression.infix().contains("atan")){
return;
}
@@ -133,14 +142,14 @@ public void testMathML_GeneralSubset() throws IOException, ExpressionException {
@ParameterizedTest
@MethodSource("testCases")
- public void testFlatten() throws ExpressionException {
+ public void testFlatten(Expression expression) throws ExpressionException {
Expression expFlattened = expression.flatten();
assertTrue(functionallyEquivalent(expression, expFlattened, false), "not equivalent: origExp='" + expression.infix() + "', expFlattened='" + expFlattened.infix() + "'");
}
@ParameterizedTest
@MethodSource("testCases")
- public void testJSCLParseInfix() throws ExpressionException, ParseException {
+ public void testJSCLParseInfix(Expression expression) throws ExpressionException, ParseException {
List tokensToAvoid = Arrays.asList(
"<",">","=","&","|","!"
);
@@ -168,7 +177,7 @@ public void testJSCLParseInfix() throws ExpressionException, ParseException {
@ParameterizedTest
@MethodSource("testCases")
- public void testJSCLSimplifyInfix() {
+ public void testJSCLSimplifyInfix(Expression expression) {
Expression expSimplified = null;
try {
expSimplified = expression.simplifyJSCL(20000, true);