User:Jiangxin/Patch load mm file with mmx file: Difference between revisions

From FreeMind
Jump to navigationJump to search
(wow account,wow accounts,buy wow account,world warcraft account)
(remove spam.)
 
Line 1: Line 1:
Recently,monluna1204 sales of Warcraft [http://www.wow-account.net wow account]is better, I would like to thank the overwhelming majority of the game World of Warcraft players [http://www.wow-account.net wow accounts].China's New World of Warcraft 80 to be opened, World of Warcraft Europe and the United States has opened 80 [http://www.wow-account.net buy wow account], 80 attract a lot of players, some new copy of the new games is all smoke, and the major forum Blog on a lot of World of Warcraft World of Warcraft players are full of praise of 80. Some new equipment to allow [http://www.wow-account.net buy wow accounts] more players the emergence of a new pursuit [http://www.wow-account.net world of warcraft account]. In fact,on the game and life, innovation is a new vitality.  
==Why this patch?==
All my .mm files are version controled using CVS/SVN. What FreeMind has scratched my personal itch:
*Some attributes of FreeMind's .mm file are not suitable for version control.  
*e.g., 'FOLDED' attribute saved in .mm file, makes documents changed frequently and unnecessarily.  


In the course of the transaction security, integrity has become the focus of attention. The majority of players for the sake of our account is absolutely safe to sell.In the near future wow account, World of Warcraft will be opening 80, I believe that there will be a lot of players will return to the family of World of Warcraft.
==How .mmx is saved.==
How the .mmx file is generated? Please see this link:
* [[User:Jiangxin/Patch_save_extra_attributes_outof_mmfile]].
 
==Overview==
When load a mindmap file(*.mm), will check whether a .*.mmx file exist at the same directory. It it exist,  
a xslt will help to join the two files into one big XML.
 
When I write the patch at 2005, I even don't know the basic knowledge of optimization of a XSLT.
*<s>Warning: this patch is immature, and it can cause trouble if your FreeMind .mm file is as large as 200KB!</s>
*<s>'''Java expert/FreeMind Funs, can you help me to make it usable.'''</s> Thank you.
 
Last week when I feel it's time to upgrade to freemind 0.9, I overview and rewrite the xslt and the patch.
 
-- [[User:Jiangxin|Jiangxin]] 02:26, 15 Mar 2007 (PDT)
 
==the XSLT==
My implementation is using a XSLT file to join the .mmx file with .mm file in runtime. The XSLT is below:
 
file : ''freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt''
=== low performance version ===
<s>
<pre><nowiki>
...
<xsl:copy>
<xsl:choose>
<xsl:when test="$mmx_nodes//node[@ID=current()/@ID]">
<xsl:for-each select="@*">
<xsl:choose>
<xsl:when test="local-name(.) = 'FOLDED'">
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:copy-of select="$mmx_nodes//node[@ID=current()/@ID]/@*" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="@*" />
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates />
</xsl:copy>
...
</nowiki></pre>
</s>
 
=== optimized version using key ===
<pre><nowiki>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Usage:
  xsltproc -stringparam mmx_file mindmap.mmx <this_xslt> mindmap.mm
-->
  <xsl:output method="xml" version="1.0" encoding="utf-8"
      indent="no" />
 
  <xsl:param name="mmx_file" />
  <xsl:variable name="indexfile" select="document($mmx_file)" />
 
  <xsl:key name="node-by-id" match="node" use="@ID"/>
 
  <xsl:template match="map">
      <map>
          <xsl:copy-of select="@*" />
          <xsl:apply-templates />
      </map>
  </xsl:template>
 
  <xsl:template match="node">
      <xsl:variable name="id" select="@ID" />
      <xsl:copy>
          <xsl:copy-of select="@*" />
          <xsl:for-each select="$indexfile">
              <xsl:copy-of select="key('node-by-id', $id)/@*" />
          </xsl:for-each>
          <xsl:apply-templates />
      </xsl:copy>
  </xsl:template>
 
  <xsl:template match="*">
    <xsl:copy-of select="."/>
  </xsl:template>
 
</xsl:stylesheet>
</nowiki></pre>
 
=== test the xslt ===
*xslt
<pre>
$ xsltproc --stringparam mmx_file subject-forum.mmx freemind_join_mm_mmx.xslt subject-forum.mm > jx.mm
</pre>
 
*saxon
<pre>
$ java -cp /usr/share/java/saxon.jar com.icl.saxon.StyleSheet test.mm freemind_join_mm_mmx.xslt  mmx_file=test.mmx
</pre>
 
*xalan
<pre>
$ java -classpath /usr/share/java/xalan2.jar org.apache.xalan.xslt.Process -IN test.mm  -XSL freemind_join_mm_mmx.xslt -PARAM mmx_file test.mmx
</pre>
 
=== Using saxon xslt engine ===
The built-in xslt engine does not work with this xslt. I choose saxon xslt engine.
 
<pre><nowiki>
System.setProperty("javax.xml.transform.TransformerFactory",
    "com.icl.saxon.TransformerFactoryImpl");
</nowiki></pre>
 
== Patch ==
<pre><nowiki>
Index: freemind/main/Tools.java
===================================================================
--- a/freemind/freemind/main/Tools.java
+++ b/freemind/freemind/main/Tools.java
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
+//OSSXP.COM: classes for .mm and .mmx join.
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.dom.DOMSource;
+import org.w3c.dom.Document;
+
public class Tools {
    //public static final Set executableExtensions = new HashSet ({ "exe",
@@ -845,7 +851,8 @@
    } catch(Exception ex) {
        freemind.main.Resources.getInstance().logException(ex);
        // exception: we take the file itself:
-         return getActualReader(file);
+         // OSSXP.COM
+         return getActualReader(file, frame);
    } finally {
        if(inputStream!= null) {
            inputStream.close();
@@ -857,10 +864,112 @@
    return new StringReader(writer.getBuffer().toString());
}
- /** Creates a default reader that just reads the given file.
- * @throws FileNotFoundException
+ /*
+ * OSSXP.COM: hacked FreeMind saved two seperate files, .mm and .mmx file.
+ * Join them in runtime using XSLT TransformerFactory.
+ * TODO: Improvement needed. the joining stage may very slow, so disable it.
*/
- public static Reader getActualReader(File file) throws FileNotFoundException {
+ public static Reader getActualReader(File file, FreeMindMain frame) throws IOException {
+     // load .mmx file...
+     String ext = Tools.getExtension(file.getName());
+     String mmxFileName = "";
+
+     // OSSXP.COM: can disable join .mm with .mmx here.
+     // if(true) return getActualReaderXml(file);
+    
+     if(!ext.equals("mm"))
+     {
+     mmxFileName = "." + file.getName()+".mmx";
+     }
+     else
+     {
+     mmxFileName = "." + Tools.removeExtension(file.getName()) + ".mmx";
+     }
+     File mmxfile = new File(file.getParent(), mmxFileName);
+    
+     if (!mmxfile.exists())
+     {
+     return getActualReaderXml(file);
+     }
+
+     URL updaterUrl = null;
+     InputStream inputStream = null;
+     Source xsltSource = null;
+     StringWriter buffwriter = null;
+     Result result = null;
+     TransformerFactory tf = null;
+     Transformer transformer = null;
+     String mmxFileFullName = mmxfile.toURI().toString();
+     try {
+         // try to convert map with xslt:
+     updaterUrl = frame.getResource(
+                 "freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt");
+         if (updaterUrl == null) {
+             throw new IllegalArgumentException(
+                     "freemind_join_mm_mmx.xslt not found.");
+         }
+         inputStream = updaterUrl.openStream();
+         xsltSource = new StreamSource(inputStream);
+         // get output:
+         buffwriter = new StringWriter();
+         result = new StreamResult(buffwriter);
+         /* OSSXP.COM: create an instance of TransformerFactory.
+         * the default xslt engine (com.sun.org.apache.xalan.internal.xsltc.trax...)
+         * may not support 'key()' in freemind_join_mm_mmx.xslt.
+         * Use saxon implement. */
+         System.setProperty("javax.xml.transform.TransformerFactory",
+         "com.icl.saxon.TransformerFactoryImpl");
+         tf = TransformerFactory.newInstance();
+         transformer = tf.newTransformer(xsltSource);
+         transformer.setParameter("mmx_file", mmxFileFullName);
+         transformer.transform(new StreamSource(file), result);
+
+     } catch (Exception ex) {
+         ex.printStackTrace();
+         // exception: we take the file itself:
+         return getActualReaderXml(file);
+     } finally {
+         if (inputStream != null) {
+             inputStream.close();
+         }
+         if (buffwriter != null) {
+             buffwriter.close();
+         }
+         inputStream = null;
+         xsltSource = null;
+         updaterUrl = null;
+         result = null;
+         transformer = null;
+         tf = null;
+     }
+     return new StringReader(buffwriter.getBuffer().toString());
+ }
+
+ /*
+ * OSSXP.COM: In this hacked version, .mm file is a true XML file.
+ * load XML file using DOM.
+ */
+ private static Reader getActualReaderXml(File file) throws IOException {
+     try
+     {
+         TransformerFactory tf = TransformerFactory.newInstance();
+         Transformer transformer = tf.newTransformer();
+         DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+         DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
+
+         Document doc = domBuilder.parse(file);
+         Source src = new DOMSource(doc);
+         StringWriter buffwriter = new StringWriter();
+         StreamResult result = new StreamResult(buffwriter);
+         transformer.transform(src, result);
+
+         return new StringReader(buffwriter.toString());
+     }
+     catch(Exception exp)
+     {
+     exp.printStackTrace();
+     }
+
    return new BufferedReader(new FileReader(file));
}
Index: freemind/modes/mindmapmode/MindMapMapModel.java
===================================================================
--- a/freemind/freemind/modes/mindmapmode/MindMapMapModel.java
+++ b/freemind/freemind/modes/mindmapmode/MindMapMapModel.java
@@ -440,7 +440,7 @@
            }
            if (mapStart.equals(EXPECTED_START_STRINGS[i])) {
                // actual version:
-                reader = Tools.getActualReader(file);
+                reader = Tools.getActualReader(file, getFrame());
                break;
            }
        }
Index: build.xml
===================================================================
--- a/freemind/build.xml
+++ b/freemind/build.xml
@@ -343,6 +343,7 @@
<include name="Resources*"/>
<include name="mindmap_menus.xml"/>
<include name="**/freemind_version_updater.xslt"/>
+ <include name="**/freemind_join_mm_mmx.xslt"/>
</fileset>
</jar>
</target>
</nowiki></pre>

Latest revision as of 06:02, 14 February 2009

Why this patch?

All my .mm files are version controled using CVS/SVN. What FreeMind has scratched my personal itch:

  • Some attributes of FreeMind's .mm file are not suitable for version control.
  • e.g., 'FOLDED' attribute saved in .mm file, makes documents changed frequently and unnecessarily.

How .mmx is saved.

How the .mmx file is generated? Please see this link:

Overview

When load a mindmap file(*.mm), will check whether a .*.mmx file exist at the same directory. It it exist, a xslt will help to join the two files into one big XML.

When I write the patch at 2005, I even don't know the basic knowledge of optimization of a XSLT.

  • Warning: this patch is immature, and it can cause trouble if your FreeMind .mm file is as large as 200KB!
  • Java expert/FreeMind Funs, can you help me to make it usable. Thank you.

Last week when I feel it's time to upgrade to freemind 0.9, I overview and rewrite the xslt and the patch.

-- Jiangxin 02:26, 15 Mar 2007 (PDT)

the XSLT

My implementation is using a XSLT file to join the .mmx file with .mm file in runtime. The XSLT is below:

file : freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt

low performance version

...
		<xsl:copy>
			<xsl:choose>
				<xsl:when test="$mmx_nodes//node[@ID=current()/@ID]">
					<xsl:for-each select="@*">
						<xsl:choose>
							<xsl:when test="local-name(.) = 'FOLDED'">
							</xsl:when>
							<xsl:otherwise>
								<xsl:copy-of select="." />
							</xsl:otherwise>
						</xsl:choose>
					</xsl:for-each>
					<xsl:copy-of select="$mmx_nodes//node[@ID=current()/@ID]/@*" />
				</xsl:when>
				<xsl:otherwise>
					<xsl:copy-of select="@*" />
				</xsl:otherwise>
			</xsl:choose>
			<xsl:apply-templates />
		</xsl:copy>
...

optimized version using key

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Usage:
   xsltproc -stringparam mmx_file mindmap.mmx <this_xslt> mindmap.mm
-->
   <xsl:output method="xml" version="1.0" encoding="utf-8"
       indent="no" />

   <xsl:param name="mmx_file" />
   <xsl:variable name="indexfile" select="document($mmx_file)" />

   <xsl:key name="node-by-id" match="node" use="@ID"/>

   <xsl:template match="map">
       <map>
           <xsl:copy-of select="@*" />
           <xsl:apply-templates />
       </map>
   </xsl:template>

   <xsl:template match="node">
       <xsl:variable name="id" select="@ID" />
       <xsl:copy>
           <xsl:copy-of select="@*" />
           <xsl:for-each select="$indexfile">
               <xsl:copy-of select="key('node-by-id', $id)/@*" />
           </xsl:for-each>
           <xsl:apply-templates />
       </xsl:copy>
   </xsl:template>

   <xsl:template match="*">
     <xsl:copy-of select="."/>
   </xsl:template>

</xsl:stylesheet>

test the xslt

  • xslt
$ xsltproc --stringparam mmx_file subject-forum.mmx freemind_join_mm_mmx.xslt subject-forum.mm > jx.mm
  • saxon
$ java -cp /usr/share/java/saxon.jar com.icl.saxon.StyleSheet test.mm freemind_join_mm_mmx.xslt  mmx_file=test.mmx
  • xalan
$ java -classpath /usr/share/java/xalan2.jar org.apache.xalan.xslt.Process -IN test.mm  -XSL freemind_join_mm_mmx.xslt -PARAM mmx_file test.mmx

Using saxon xslt engine

The built-in xslt engine does not work with this xslt. I choose saxon xslt engine.

System.setProperty("javax.xml.transform.TransformerFactory", 
    "com.icl.saxon.TransformerFactoryImpl");

Patch

Index: freemind/main/Tools.java
===================================================================
--- a/freemind/freemind/main/Tools.java 
+++ b/freemind/freemind/main/Tools.java 
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 
+//OSSXP.COM: classes for .mm and .mmx join.
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.dom.DOMSource;
+import org.w3c.dom.Document;
+
 public class Tools {
 
     //public static final Set executableExtensions = new HashSet ({ "exe",
@@ -845,7 +851,8 @@
 	    } catch(Exception ex) {
 	        freemind.main.Resources.getInstance().logException(ex);
 	        // exception: we take the file itself:
-	        return getActualReader(file);
+	        // OSSXP.COM
+	        return getActualReader(file, frame);
 	    } finally {
 	        if(inputStream!= null) {
 	            inputStream.close();
@@ -857,10 +864,112 @@
 	    return new StringReader(writer.getBuffer().toString());
 	}
 
-	/** Creates a default reader that just reads the given file.
-	 * @throws FileNotFoundException
+	/*
+	 * OSSXP.COM: hacked FreeMind saved two seperate files, .mm and .mmx file.
+	 * Join them in runtime using XSLT TransformerFactory.
+	 * TODO: Improvement needed. the joining stage may very slow, so disable it.
 	 */
-	public static Reader getActualReader(File file) throws FileNotFoundException {
+	public static Reader getActualReader(File file, FreeMindMain frame) throws IOException {
+	    // load .mmx file...
+	    String ext = Tools.getExtension(file.getName());
+	    String mmxFileName = "";
+
+	    // OSSXP.COM: can disable join .mm with .mmx here.
+	    // if(true) return getActualReaderXml(file);
+	    
+	    if(!ext.equals("mm")) 
+	    {
+	    	mmxFileName = "." + file.getName()+".mmx";
+	    }
+	    else 
+	    {
+	    	mmxFileName = "." + Tools.removeExtension(file.getName()) + ".mmx";
+	    }
+	    File mmxfile = new File(file.getParent(), mmxFileName);
+	    
+	    if (!mmxfile.exists())
+	    {
+	    	return getActualReaderXml(file);
+	    }
+
+	    URL updaterUrl = null;
+	    InputStream inputStream = null;
+	    Source xsltSource = null;
+	    StringWriter buffwriter = null;
+	    Result result = null;
+	    TransformerFactory tf = null;
+	    Transformer transformer = null;
+	    String mmxFileFullName = mmxfile.toURI().toString();
+	    try {
+	        // try to convert map with xslt:
+	    	updaterUrl = frame.getResource(
+	                "freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt");
+	        if (updaterUrl == null) {
+	            throw new IllegalArgumentException(
+	                    "freemind_join_mm_mmx.xslt not found.");
+	        }
+	        inputStream = updaterUrl.openStream();
+	        xsltSource = new StreamSource(inputStream);
+	        // get output:
+	        buffwriter = new StringWriter();
+	        result = new StreamResult(buffwriter);
+	        /* OSSXP.COM: create an instance of TransformerFactory.
+	         * the default xslt engine (com.sun.org.apache.xalan.internal.xsltc.trax...) 
+	         * may not support 'key()' in freemind_join_mm_mmx.xslt. 
+	         * Use saxon implement. */
+	        System.setProperty("javax.xml.transform.TransformerFactory", 
+	        		"com.icl.saxon.TransformerFactoryImpl");
+	        tf = TransformerFactory.newInstance();
+	        transformer = tf.newTransformer(xsltSource);
+	        transformer.setParameter("mmx_file", mmxFileFullName);
+	        transformer.transform(new StreamSource(file), result);
+
+	    } catch (Exception ex) {
+	        ex.printStackTrace();
+	        // exception: we take the file itself:
+	        return getActualReaderXml(file);
+	    } finally {
+	        if (inputStream != null) {
+	            inputStream.close();
+	        }
+	        if (buffwriter != null) {
+	            buffwriter.close();
+	        }
+	        inputStream = null;
+	        xsltSource = null;
+	        updaterUrl = null;
+	        result = null;
+	        transformer = null;
+	        tf = null;
+	    }
+	    return new StringReader(buffwriter.getBuffer().toString());
+	}
+
+	/* 
+	 * OSSXP.COM: In this hacked version, .mm file is a true XML file.
+	 * load XML file using DOM.
+	 */
+	private static Reader getActualReaderXml(File file) throws IOException {
+	    try
+	    {
+	        TransformerFactory tf = TransformerFactory.newInstance();
+	        Transformer transformer = tf.newTransformer();
+	        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+	        DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
+
+	        Document doc = domBuilder.parse(file);
+	        Source src = new DOMSource(doc);
+	        StringWriter buffwriter = new StringWriter();
+	        StreamResult result = new StreamResult(buffwriter);
+	        transformer.transform(src, result);
+
+	        return new StringReader(buffwriter.toString());
+	    }
+	    catch(Exception exp)
+	    {
+	    	exp.printStackTrace();
+	    }
+
 	    return new BufferedReader(new FileReader(file));
 	}
 
Index: freemind/modes/mindmapmode/MindMapMapModel.java
===================================================================
--- a/freemind/freemind/modes/mindmapmode/MindMapMapModel.java 
+++ b/freemind/freemind/modes/mindmapmode/MindMapMapModel.java 
@@ -440,7 +440,7 @@
             }
             if (mapStart.equals(EXPECTED_START_STRINGS[i])) {
                 // actual version:
-                reader = Tools.getActualReader(file);
+                reader = Tools.getActualReader(file, getFrame());
                 break;
             }
         }
Index: build.xml
===================================================================
--- a/freemind/build.xml 
+++ b/freemind/build.xml 
@@ -343,6 +343,7 @@
 				<include name="Resources*"/>
 				<include name="mindmap_menus.xml"/>
 				<include name="**/freemind_version_updater.xslt"/>
+				<include name="**/freemind_join_mm_mmx.xslt"/>
 			</fileset>
 		</jar>
 	</target>