001 package net.sourceforge.jeuclid.test.content;
002
003 import java.util.HashMap;
004 import java.util.LinkedHashSet;
005 import java.util.Map;
006 import java.util.Set;
007
008 import javax.annotation.Nonnull;
009 import javax.annotation.Nullable;
010 import javax.xml.xpath.XPath;
011 import javax.xml.xpath.XPathConstants;
012 import javax.xml.xpath.XPathExpression;
013 import javax.xml.xpath.XPathFactory;
014
015 import junit.framework.Assert;
016 import net.sourceforge.jeuclid.DOMBuilder;
017 import net.sourceforge.jeuclid.MathMLParserSupport;
018 import net.sourceforge.jeuclid.MathMLSerializer;
019 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
020 import net.sourceforge.jeuclid.elements.support.NamespaceContextAdder;
021
022 import org.junit.Ignore;
023 import org.junit.Test;
024 import org.w3c.dom.Document;
025 import org.w3c.dom.Element;
026 import org.w3c.dom.NamedNodeMap;
027 import org.w3c.dom.Node;
028 import org.w3c.dom.NodeList;
029
030 public class ContentTransformationTest {
031
032 private void testbyXpath(final String mathWithContent,
033 final String... tests) throws Exception {
034
035 final XPathFactory factory = XPathFactory.newInstance();
036 final XPath xpath = factory.newXPath();
037 xpath.setNamespaceContext(new NamespaceContextAdder("m",
038 AbstractJEuclidElement.URI, null));
039
040 final Document dorig = MathMLParserSupport.parseString("<math>"
041 + mathWithContent + "</math>");
042 final Document d = DOMBuilder.getInstance().createJeuclidDom(dorig,
043 true, true);
044
045 final int count = tests.length / 2;
046 for (int i = 0; i < count; i++) {
047 final String expr = tests[i * 2];
048 final String text = tests[i * 2 + 1];
049
050 final XPathExpression xpathExpr = xpath.compile("/m:math" + expr);
051 final Node n = (Node) xpathExpr.evaluate(d, XPathConstants.NODE);
052 Assert.assertNotNull(n);
053 Assert.assertEquals(text, n.getTextContent());
054 }
055 }
056
057 public void testByDirectComparison(final String contentMath,
058 final String presentationMath) throws Exception {
059 final Document dorigcontent = MathMLParserSupport.parseString("<math>"
060 + contentMath + "</math>");
061 final Document dcontent = DOMBuilder.getInstance().createJeuclidDom(
062 dorigcontent, true, true);
063 final Document dorigpresentation = MathMLParserSupport
064 .parseString("<math>" + presentationMath + "</math>");
065 final Document dpresentation = DOMBuilder.getInstance()
066 .createJeuclidDom(dorigpresentation, true, true);
067
068 this.removeDoubleNS(dcontent, null);
069 this.removeDoubleNS(dpresentation, null);
070
071 final String cString = MathMLSerializer.serializeDocument(dcontent,
072 false, true);
073 final String pString = MathMLSerializer.serializeDocument(
074 dpresentation, false, true);
075
076 Assert.assertEquals(pString, cString);
077 }
078
079 private void removeDoubleNS(@Nonnull final Node node,
080 @Nullable final Map<String, Set<String>> namespaces) {
081 if (node.getNodeType() == Node.TEXT_NODE) {
082 return;
083 }
084 final Map<String, Set<String>> contextHere = new HashMap<String, Set<String>>();
085 if (namespaces != null) {
086 contextHere.putAll(namespaces);
087 }
088 final NamedNodeMap allAttrs = node.getAttributes();
089 if (allAttrs != null) {
090 for (int i = 0; i < allAttrs.getLength(); i++) {
091 final Node attr = allAttrs.item(i);
092 if (attr.getNodeName().startsWith("xmlns")) {
093 String prefix = attr.getLocalName();
094 final String namespace = attr.getNodeValue();
095 if ("xmlns".equals(prefix)) {
096 prefix = "";
097 }
098
099 final Set<String> currentlyKnown = contextHere
100 .get(namespace);
101 final Set<String> newSet = new LinkedHashSet<String>();
102 if (currentlyKnown != null) {
103 newSet.addAll(currentlyKnown);
104 }
105 if (!newSet.isEmpty()) {
106 ((Element) node).removeAttribute(attr.getNodeName());
107 ((Element) node).removeAttributeNS(
108 attr.getNamespaceURI(), attr.getLocalName());
109 }
110 newSet.add(prefix);
111 contextHere.put(namespace, newSet);
112 }
113 }
114 }
115
116 final String name = node.getNodeName();
117 String prefix;
118 final String[] elements = name.split(":");
119 if (elements.length == 1) {
120 prefix = "";
121 } else {
122 prefix = elements[0];
123 }
124
125 for (final Map.Entry<String, Set<String>> nsEntry : contextHere
126 .entrySet()) {
127 final Set<String> prefixes = nsEntry.getValue();
128
129 if (prefixes.contains(prefix)) {
130 final String first = prefixes.iterator().next();
131 if (!first.equals(prefix)) {
132 final StringBuilder newName = new StringBuilder(first);
133 if (first.length()!=0) {
134 newName.append(':');
135 }
136 newName.append(node.getLocalName());
137 ((Element) node).setPrefix(first);
138 }
139 }
140 }
141
142
143 final NodeList children = node.getChildNodes();
144 if (children != null) {
145 for (int i = 0; i < children.getLength(); i++) {
146 this.removeDoubleNS(children.item(i), contextHere);
147 }
148 }
149 }
150
151 @Test
152 public void testSimpleTransformations() throws Exception {
153 this.testbyXpath("<apply><plus/><cn>5</cn><ci>x</ci></apply>",
154 "/m:mrow/m:mn[1]", "5", "/m:mrow/m:mo[1]", "+",
155 "/m:mrow/m:mi[1]", "x");
156 this.testbyXpath("<apply><times/><cn>5</cn><ci>x</ci></apply>",
157 "/m:mrow/m:mn[1]", "5", "/m:mrow/m:mo[1]", "\u2062",
158 "/m:mrow/m:mi[1]", "x");
159 }
160
161 @Test
162 public void testSimpleTransformations2() throws Exception {
163 this.testByDirectComparison(
164 "<apply><plus/><cn>5</cn><ci>x</ci></apply>",
165 "<mrow><mn>5</mn><mo>+</mo><mi>x</mi></mrow>");
166 this.testByDirectComparison(
167 "<apply><times/><cn>5</cn><ci>x</ci></apply>",
168 "<mrow><mn>5</mn><mo>⁢</mo><mi>x</mi></mrow>");
169 }
170
171 // Not yet functional.
172 @Ignore
173 @Test
174 public void testContentParam() throws Exception {
175 this.testbyXpath("<apply><times/><cn>5</cn><ci>x</ci></apply>",
176 "/m:mrow/m:mn[1]", "5", "/m:mrow/m:mo[1]", "\u00d7",
177 "/m:mrow/m:mi[1]", "x");
178 }
179 }