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 }