OSDN Git Service

Silk -> XML
authorleo <leo@ae02f08e-27ec-0310-ae8c-8ba02fe2eafd>
Sun, 15 Feb 2009 09:32:12 +0000 (09:32 +0000)
committerleo <leo@ae02f08e-27ec-0310-ae8c-8ba02fe2eafd>
Sun, 15 Feb 2009 09:32:12 +0000 (09:32 +0000)
git-svn-id: http://www.xerial.org/svn/project/XerialJ/trunk/xerial-core@2976 ae02f08e-27ec-0310-ae8c-8ba02fe2eafd

src/main/java/org/xerial/json/JSONWriter.java
src/main/java/org/xerial/silk/SilkUtil.java [new file with mode: 0644]
src/main/java/org/xerial/silk/SilkWalker.java
src/main/java/org/xerial/util/xml/XMLAttribute.java
src/main/java/org/xerial/util/xml/XMLGenerator.java
src/test/java/org/xerial/silk/SilkUtilTest.java [new file with mode: 0644]

index 1b3ec90..ac6acf1 100644 (file)
@@ -25,6 +25,7 @@
 package org.xerial.json;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.Writer;
 import java.util.LinkedList;
@@ -42,7 +43,7 @@ import org.xerial.util.bean.BeanUtil;
  */
 public class JSONWriter
 {
-    private final Writer writer;
+    private final PrintWriter writer;
 
     enum JSONState {
         InObject, InArray, InString, Root, Unknown
@@ -53,7 +54,7 @@ public class JSONWriter
 
     public JSONWriter(Writer writer)
     {
-        this.writer = writer;
+        this.writer = new PrintWriter(writer);
         stateStack.add(JSONState.Root);
         elementCountStack.add(0);
     }
@@ -89,41 +90,41 @@ public class JSONWriter
         elementCountStack.add(++count);
     }
 
-    public void startObject() throws IOException
+    public void startObject()
     {
         if (getCurrentState() == JSONState.InArray)
             putComma();
-        writer.append("{");
+        writer.print("{");
         pushState(JSONState.InObject);
     }
 
-    public void endObject() throws IOException
+    public void endObject()
     {
         if (getCurrentState() != JSONState.InObject)
             throw new XerialError(JSONErrorCode.NotInAJSONObject, "cannot end the object outside of the JSON object");
-        writer.append("}");
+        writer.print("}");
         popState();
 
         if (getCurrentState() == JSONState.InArray)
             incrementElementCount();
     }
 
-    public void startArray() throws IOException
+    public void startArray()
     {
-        writer.append("[");
+        writer.print("[");
         pushState(JSONState.InArray);
     }
 
-    public void endArray() throws IOException
+    public void endArray()
     {
         if (getCurrentState() != JSONState.InArray)
             throw new XerialError(JSONErrorCode.NotInAJSONArray, "cannot end the arry outside of the JSON array");
 
-        writer.append("]");
+        writer.print("]");
         popState();
     }
 
-    public void startString() throws IOException
+    public void startString()
     {
         if (getCurrentState() == JSONState.InArray)
             throw new XerialError(JSONErrorCode.NotInAJSONArray,
@@ -133,14 +134,14 @@ public class JSONWriter
         pushState(JSONState.InString);
     }
 
-    public void startString(String key) throws IOException
+    public void startString(String key)
     {
         outputKeyPart(key);
         writer.append("\"");
         pushState(JSONState.InString);
     }
 
-    public void append(String stringFragment) throws IOException
+    public void append(String stringFragment)
     {
         if (getCurrentState() != JSONState.InString)
             throw new XerialError(JSONErrorCode.NotInAJSONString,
@@ -158,16 +159,16 @@ public class JSONWriter
         popState();
     }
 
-    public void startArray(String key) throws IOException
+    public void startArray(String key)
     {
         if (getCurrentState() != JSONState.InObject)
             throw new XerialError(JSONErrorCode.NotInAJSONObject,
                     "cannot start a keyed array outside of the JSON object");
 
         if (getPreviousElementCount() > 0)
-            writer.append(",");
-        writer.append(doubleQuote(key));
-        writer.append(":[");
+            writer.print(",");
+        writer.print(doubleQuote(key));
+        writer.print(":[");
         incrementElementCount();
         pushState(JSONState.InArray);
     }
@@ -233,10 +234,10 @@ public class JSONWriter
         incrementElementCount();
     }
 
-    private void putComma() throws IOException
+    private void putComma()
     {
         if (getPreviousElementCount() > 0)
-            writer.append(",");
+            writer.print(",");
     }
 
     public void put(String key, String value) throws IOException
@@ -283,6 +284,7 @@ public class JSONWriter
      * @param key
      * @param input
      * @throws IOException
+     * @throws IOException
      */
     public void putString(String key, Reader input) throws IOException
     {
@@ -302,7 +304,7 @@ public class JSONWriter
         incrementElementCount();
     }
 
-    private void outputKeyPart(String key) throws IOException
+    private void outputKeyPart(String key)
     {
         if (getCurrentState() != JSONState.InObject)
             throw new XerialError(JSONErrorCode.NotInAJSONObject,
@@ -313,12 +315,12 @@ public class JSONWriter
         writer.append(":");
     }
 
-    public void flush() throws IOException
+    public void flush()
     {
         writer.flush();
     }
 
-    public void endJSON() throws IOException
+    public void endJSON()
     {
         for (ListIterator<JSONState> it = stateStack.listIterator(stateStack.size()); it.hasPrevious();)
         {
diff --git a/src/main/java/org/xerial/silk/SilkUtil.java b/src/main/java/org/xerial/silk/SilkUtil.java
new file mode 100644 (file)
index 0000000..df4bf64
--- /dev/null
@@ -0,0 +1,220 @@
+/*--------------------------------------------------------------------------\r
+ *  Copyright 2009 Taro L. Saito\r
+ *\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ *--------------------------------------------------------------------------*/\r
+//--------------------------------------\r
+// XerialJ\r
+//\r
+// SilkUtil.java\r
+// Since: 2009/02/13 21:15:32\r
+//\r
+// $URL$\r
+// $Author$\r
+//--------------------------------------\r
+package org.xerial.silk;\r
+\r
+import java.io.IOException;\r
+import java.io.StringWriter;\r
+import java.io.Writer;\r
+import java.net.URL;\r
+import java.util.ArrayDeque;\r
+import java.util.Deque;\r
+\r
+import org.xerial.core.XerialError;\r
+import org.xerial.core.XerialException;\r
+import org.xerial.json.JSONWriter;\r
+import org.xerial.util.tree.TreeEvent;\r
+import org.xerial.util.tree.TreeVisitor;\r
+import org.xerial.util.tree.TreeVisitorBase;\r
+import org.xerial.util.tree.TreeWalker;\r
+import org.xerial.util.xml.XMLAttribute;\r
+import org.xerial.util.xml.XMLErrorCode;\r
+import org.xerial.util.xml.XMLGenerator;\r
+\r
+/**\r
+ * Utilities for handling Silk file format.\r
+ * \r
+ * @author leo\r
+ * \r
+ */\r
+public class SilkUtil\r
+{\r
+    public static String toXML(URL silkSource) throws IOException, XerialException\r
+    {\r
+        StringWriter buf = new StringWriter();\r
+        toXML(silkSource, buf);\r
+        return buf.toString();\r
+    }\r
+\r
+    /**\r
+     * Convert the silk file into XML\r
+     * \r
+     * @param silkSource\r
+     * @param out\r
+     * @throws IOException\r
+     * @throws XerialException\r
+     */\r
+    public static void toXML(URL silkSource, Writer out) throws IOException, XerialException\r
+    {\r
+        SilkWalker walker = new SilkWalker(silkSource);\r
+        XMLBuilder builder = new XMLBuilder(out);\r
+        walker.walk(builder);\r
+\r
+    }\r
+\r
+    /**\r
+     * \r
+     * <pre>\r
+     * 1:visit -&gt; 2:visit : pop(1), startTag(1, value=&quot;..&quot;), push(2:visit)\r
+     * 1:visit -&gt; 2:text : pop(1), startTag(1, value=&quot;..&quot;), text(2:text) \r
+     * 1:visit -&gt; 2:leave : pop(1), selfCloseTag(1, value=&quot;..&quot;)\r
+     * </pre>\r
+     * \r
+     * @author leo\r
+     * \r
+     */\r
+    private static class XMLBuilder extends TreeVisitorBase\r
+    {\r
+        final XMLGenerator xout;\r
+        final Deque<TreeEvent> eventQueue = new ArrayDeque<TreeEvent>();\r
+\r
+        public XMLBuilder(Writer out)\r
+        {\r
+            xout = new XMLGenerator(out);\r
+        }\r
+\r
+        private void popQueue()\r
+        {\r
+            if (!eventQueue.isEmpty())\r
+            {\r
+                TreeEvent prev = eventQueue.removeLast();\r
+\r
+                switch (prev.event)\r
+                {\r
+                case VISIT:\r
+                    if (prev.nodeValue == null)\r
+                        xout.startTag(prev.nodeName);\r
+                    else\r
+                        xout.startTag(prev.nodeName, new XMLAttribute("value", prev.nodeValue));\r
+                    break;\r
+                default:\r
+                    throw new XerialError(XMLErrorCode.INVALID_XML_STRUCTURE);\r
+                }\r
+            }\r
+\r
+        }\r
+\r
+        @Override\r
+        public void visitNode(String nodeName, String immediateNodeValue, TreeWalker walker) throws XerialException\r
+        {\r
+            popQueue();\r
+            eventQueue.addLast(new TreeEvent(TreeEvent.EventType.VISIT, nodeName, immediateNodeValue));\r
+        }\r
+\r
+        @Override\r
+        public void text(String textDataFragment, TreeWalker walker) throws XerialException\r
+        {\r
+            popQueue();\r
+            xout.text(textDataFragment);\r
+        }\r
+\r
+        @Override\r
+        public void leaveNode(String nodeName, TreeWalker walker) throws XerialException\r
+        {\r
+            if (!eventQueue.isEmpty())\r
+            {\r
+                TreeEvent prev = eventQueue.removeLast();\r
+\r
+                switch (prev.event)\r
+                {\r
+                case VISIT:\r
+                    if (prev.nodeValue == null)\r
+                        xout.selfCloseTag(prev.nodeName);\r
+                    else\r
+                        xout.element(prev.nodeName, prev.nodeValue);\r
+                }\r
+            }\r
+            else\r
+                xout.endTag();\r
+        }\r
+\r
+        @Override\r
+        public void init(TreeWalker walker) throws XerialException\r
+        {\r
+            visitNode("silk", null, walker);\r
+        }\r
+\r
+        @Override\r
+        public void finish(TreeWalker walker) throws XerialException\r
+        {\r
+            leaveNode("silk", walker);\r
+            xout.endDocument();\r
+        }\r
+    }\r
+\r
+    public static void toJSON(URL silkSource, Writer out) throws IOException, XerialException\r
+    {\r
+        SilkWalker walker = new SilkWalker(silkSource);\r
+        JSONBuilder builder = new JSONBuilder(out);\r
+        walker.walk(builder);\r
+    }\r
+\r
+    private static class JSONBuilder implements TreeVisitor\r
+    {\r
+        final JSONWriter jout;\r
+\r
+        public JSONBuilder(Writer out)\r
+        {\r
+            jout = new JSONWriter(out);\r
+        }\r
+\r
+        public void finish(TreeWalker walker) throws XerialException\r
+        {\r
+            jout.endArray();\r
+\r
+        }\r
+\r
+        public void init(TreeWalker walker) throws XerialException\r
+        {\r
+            jout.startArray();\r
+\r
+        }\r
+\r
+        public void leaveNode(String nodeName, TreeWalker walker) throws XerialException\r
+        {\r
+        // TODO Auto-generated method stub\r
+\r
+        }\r
+\r
+        public void text(String textDataFragment, TreeWalker walker) throws XerialException\r
+        {\r
+        // TODO Auto-generated method stub\r
+\r
+        }\r
+\r
+        public void visitNode(String nodeName, String immediateNodeValue, TreeWalker walker) throws XerialException\r
+        {\r
+        // TODO Auto-generated method stub\r
+\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * Forbid construction\r
+     */\r
+    protected SilkUtil()\r
+    {}\r
+\r
+}\r
index eff17f5..56e69c6 100644 (file)
@@ -39,6 +39,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.xerial.core.XerialError;
+import org.xerial.core.XerialErrorCode;
 import org.xerial.core.XerialException;
 import org.xerial.json.JSONArray;
 import org.xerial.json.JSONException;
@@ -70,10 +72,6 @@ import org.xerial.util.tree.TreeWalker;
 /**
  * {@link TreeWalker} implementation of the Silk format.
  * 
- * <pre>
- * &#064;
- * </pre>
- * 
  * @author leo
  * 
  */
@@ -149,7 +147,7 @@ public class SilkWalker implements TreeWalker
      * @param input
      *            `@throws IOException
      */
-    public SilkWalker(InputStream input) throws IOException
+    protected SilkWalker(InputStream input) throws IOException
     {
         this.parser = new SilkPullParser(input);
         init();
@@ -161,7 +159,7 @@ public class SilkWalker implements TreeWalker
      * @param input
      * @throws IOException
      */
-    public SilkWalker(Reader input) throws IOException
+    protected SilkWalker(Reader input) throws IOException
     {
         this.parser = new SilkPullParser(input);
         init();
@@ -178,12 +176,12 @@ public class SilkWalker implements TreeWalker
         init();
     }
 
-    public SilkWalker(URL resource) throws IOException
+    public SilkWalker(URL resourcePath) throws IOException
     {
-        String path = resource.toExternalForm();
+        String path = resourcePath.toExternalForm();
         int fileNamePos = path.lastIndexOf("/");
         this.resourceBasePath = fileNamePos > 0 ? path.substring(0, fileNamePos) : null;
-        this.parser = new SilkPullParser(new BufferedReader(new InputStreamReader(resource.openStream())));
+        this.parser = new SilkPullParser(new BufferedReader(new InputStreamReader(resourcePath.openStream())));
         init();
     }
 
@@ -311,7 +309,7 @@ public class SilkWalker implements TreeWalker
         {
             while (!builder.hasFinished())
             {
-                step();
+                stepNext();
             }
         }
         finally
@@ -322,6 +320,10 @@ public class SilkWalker implements TreeWalker
         return builder.getSubtreeRoot();
     }
 
+    /**
+     * If this stack is not empty, we must disable event reporting to the
+     * {@link TreeVisitor}
+     */
     private ArrayDeque<String> skipNodeStack = new ArrayDeque<String>();
 
     public void skipDescendants()
@@ -332,23 +334,48 @@ public class SilkWalker implements TreeWalker
             skipNodeStack.addLast(currentEvent.nodeName);
     }
 
+    /**
+     * Enqueues a visit event.
+     * 
+     * @param nodeName
+     * @param immediateNodeValue
+     * @throws XerialException
+     */
     private void visit(String nodeName, String immediateNodeValue) throws XerialException
     {
         eventQueue.addLast(new TreeEvent(TreeEvent.EventType.VISIT, nodeName, immediateNodeValue));
     }
 
+    /**
+     * Enqueues a leave event
+     * 
+     * @param nodeName
+     * @throws XerialException
+     */
     private void leave(String nodeName) throws XerialException
     {
         eventQueue.addLast(new TreeEvent(TreeEvent.EventType.LEAVE, nodeName, null));
     }
 
+    /**
+     * Enqueues a text event
+     * 
+     * @param textFragment
+     * @throws XerialException
+     */
     private void text(String textFragment) throws XerialException
     {
         eventQueue.addLast(new TreeEvent(TreeEvent.EventType.TEXT, null, textFragment));
 
     }
 
-    private void closeUpTo(int newIndentLevel) throws XerialException
+    /**
+     * Closed pre-opened contexts up to the specified indent level
+     * 
+     * @param newIndentLevel
+     * @throws XerialException
+     */
+    private void closeContextUpTo(int newIndentLevel) throws XerialException
     {
         //        if (newIndentLevel == SilkNode.NO_INDENT)
         //            newIndentLevel = contextNodeStack.isEmpty() ? 0 : contextNodeStack.peekLast().getIndentLevel() + 1;
@@ -362,26 +389,32 @@ public class SilkWalker implements TreeWalker
                 //outputDataCountStack.removeLast();
 
                 if (node.getOccurrence() != SilkNodeOccurrence.TABBED_SEQUENCE)
-                    closeContext(node);
+                {
+                    // close context
+                    String nodeName = node.getName();
+                    leave(nodeName);
+                }
             }
             else
                 return;
         }
     }
 
-    private void closeContext(SilkNode node) throws XerialException
-    {
-        String nodeName = node.getName();
-        leave(nodeName);
-    }
-
-    private void openContext(SilkNode node, TreeVisitor visitor) throws XerialException
+    /**
+     * Opens a new context for the given node
+     * 
+     * @param node
+     *            new context node
+     * @param visitor
+     * @throws XerialException
+     */
+    private void openContext(SilkNode node) throws XerialException
     {
         int indentLevel = node.getIndentLevel();
         if (indentLevel != SilkNode.NO_INDENT)
             indentLevel += indentationOffset;
 
-        closeUpTo(indentLevel);
+        closeContextUpTo(indentLevel);
 
         contextNodeStack.addLast(node);
         //outputDataCountStack.addLast(0);
@@ -393,8 +426,10 @@ public class SilkWalker implements TreeWalker
 
         SilkValue textValue = node.getValue();
 
+        // process text values attached to the node
         if (textValue != null)
         {
+            // When the text data is JSON, traverses the JSON data 
             if (textValue.isJSON())
             {
                 visit(nodeName, null);
@@ -412,30 +447,44 @@ public class SilkWalker implements TreeWalker
             }
             else if (textValue.isFunction())
             {
+                // evaluate the function 
                 visit(nodeName, null);
                 SilkFunction function = SilkFunction.class.cast(textValue);
-                evalFunction(function, visitor);
+                evalFunction(function);
 
                 return;
             }
             else
+            {
+                // Simple text value will be reported as it is.
                 visit(nodeName, textValue.toString());
+            }
         }
         else
+        {
+            // Report a visit event without text value
             visit(nodeName, null);
+        }
 
-        // traverse attribute nodes with text values
+        // Traverse attribute nodes which have text values. If no text value is specified for an attribute, 
+        // this attribute is a schema element for the following DATA_LINE 
         for (SilkNode eachChild : node.getChildNodes())
         {
             if (eachChild.hasValue())
             {
-                openContext(eachChild, visitor);
+                openContext(eachChild);
             }
         }
 
     }
 
-    private void evalFunction(SilkFunction function, TreeVisitor visitor) throws XerialException
+    /**
+     * Evaluate the function
+     * 
+     * @param function
+     * @throws XerialException
+     */
+    private void evalFunction(SilkFunction function) throws XerialException
     {
         if (!skipNodeStack.isEmpty())
             return; // skip evaluation
@@ -446,6 +495,7 @@ public class SilkWalker implements TreeWalker
             _logger.error(String.format("plugin %s not found", function.getName()));
             return;
         }
+        // fill the function argument to the plugin instance
         populate(plugin, function.getArgumentList());
         plugin.eval(new SilkEnvImpl(function, visitor));
 
@@ -468,14 +518,19 @@ public class SilkWalker implements TreeWalker
 
         while (hasNext())
         {
-            step();
+            stepNext();
         }
 
     }
 
-    private void step() throws XerialException
+    /**
+     * Consume the next event, and call its corresponding visitor event.
+     * 
+     * @throws XerialException
+     */
+    private void stepNext() throws XerialException
     {
-        currentEvent = next();
+        currentEvent = getNextEvent();
         //_logger.info("step: " + currentEvent);
 
         switch (currentEvent.event)
@@ -517,8 +572,17 @@ public class SilkWalker implements TreeWalker
 
     }
 
+    /**
+     * Has finished reading the stream?
+     */
     private boolean hasFinished = false;
 
+    /**
+     * Is next event available?
+     * 
+     * @return true if there are remaining events, otherwise fales
+     * @throws XerialException
+     */
     private boolean hasNext() throws XerialException
     {
         if (eventQueue.isEmpty())
@@ -533,23 +597,37 @@ public class SilkWalker implements TreeWalker
             return true;
     }
 
-    private TreeEvent next() throws XerialException
+    /**
+     * Retrieves the next event from the queue. If the event queue is empty,
+     * fill the queue with the next event
+     * 
+     * @return the next event.
+     * @throws XerialException
+     */
+    private TreeEvent getNextEvent() throws XerialException
     {
         if (!eventQueue.isEmpty())
             return eventQueue.removeFirst();
 
         if (hasFinished)
-            return null;
+            throw new XerialError(XerialErrorCode.INVALID_STATE,
+                    "hasNext() value must be checked before calling getNextEvent()");
 
         fillQueue();
-        return next();
+        return getNextEvent();
     }
 
+    /**
+     * Fill the queue by retrieving the next event from the pull parser.
+     * 
+     * @throws XerialException
+     */
     private void fillQueue() throws XerialException
     {
         if (!parser.hasNext())
         {
-            closeUpTo(indentationOffset);
+            // no more input data
+            closeContextUpTo(indentationOffset);
             hasFinished = true;
             return;
         }
@@ -567,15 +645,15 @@ public class SilkWalker implements TreeWalker
         case NODE:
             // push context node
             SilkNode newContextNode = SilkNode.class.cast(currentEvent.getElement());
-            openContext(newContextNode, visitor);
+            openContext(newContextNode);
             break;
         case FUNCTION:
             SilkFunction function = SilkFunction.class.cast(currentEvent.getElement());
-            evalFunction(function, visitor);
+            evalFunction(function);
             break;
         case DATA_LINE:
 
-            // pop the context stack up to the node with stream data node occurrence
+            // pop the context stack until finding a node for stream data node occurrence
             while (!contextNodeStack.isEmpty())
             {
                 SilkNode node = contextNodeStack.peekLast();
@@ -729,8 +807,18 @@ public class SilkWalker implements TreeWalker
 
     }
 
+    /**
+     * Plugin holder
+     */
     private static Map<String, Class<SilkFunctionPlugin>> pluginTable = null;
 
+    /**
+     * Get the plugin of the specified name
+     * 
+     * @param name
+     *            plugin name
+     * @return plugin instance or null if no corresponding plugin is found.
+     */
     private SilkFunctionPlugin getPlugin(String name)
     {
         Class<SilkFunctionPlugin> pluginClass = getPluginTable().get(name);
@@ -772,6 +860,14 @@ public class SilkWalker implements TreeWalker
         return pluginTable;
     }
 
+    /**
+     * Information of the function (plugin) arguments (
+     * {@link SilkFunctionArgument}) described in the Class definition, which
+     * implements {@link SilkFunctionPlugin}.
+     * 
+     * @author leo
+     * 
+     */
     private static class PluginField
     {
         Field field;
@@ -871,12 +967,25 @@ public class SilkWalker implements TreeWalker
 
     }
 
-    private void populate(SilkFunctionPlugin plugin, List<SilkFunctionArg> args)
+    /**
+     * Fill the plug-in argument fields with the given arguments
+     * 
+     * @param plugin
+     *            plug-in instance.
+     * @param args
+     *            function arguments.
+     */
+    private static void populate(SilkFunctionPlugin plugin, List<SilkFunctionArg> args)
     {
         PluginHolder holder = new PluginHolder(plugin.getClass());
         holder.populate(plugin, args);
     }
 
+    /**
+     * Get the context node
+     * 
+     * @return
+     */
     private SilkNode getContextNode()
     {
         if (contextNodeStack.isEmpty())
index 1d6501a..3a62a4d 100644 (file)
@@ -79,8 +79,9 @@ public class XMLAttribute
 
     public XMLAttribute add(String attributeName, String attributeValue)
     {
-        _attributeNameList.add(attributeName);
-        _attributeValue.put(attributeName, attributeValue);
+        String name = XMLGenerator.replaceWhiteSpaces(attributeName);
+        _attributeNameList.add(name);
+        _attributeValue.put(name, attributeValue);
         return this;
     }
 
@@ -119,7 +120,7 @@ public class XMLAttribute
         Set< ? > keySet = properties.keySet();
         for (Object attributeObj : keySet)
         {
-            String attribute = attributeObj.toString();
+            String attribute = XMLGenerator.replaceWhiteSpaces(attributeObj.toString());
             String value = properties.getProperty(attribute);
             this.add(attribute, value);
         }
@@ -130,7 +131,7 @@ public class XMLAttribute
         Set< ? > keySet = properties.keySet();
         for (Object attributeObj : keySet)
         {
-            String attribute = attributeObj.toString();
+            String attribute = XMLGenerator.replaceWhiteSpaces(attributeObj.toString());
             String value = properties.get(attribute).toString();
             this.add(attribute, value);
         }
@@ -181,6 +182,6 @@ public class XMLAttribute
             return returnString;
     }
 
-    protected LinkedList<String>      _attributeNameList = new LinkedList<String>();
-    protected HashMap<String, String> _attributeValue    = new HashMap<String, String>();
+    protected LinkedList<String> _attributeNameList = new LinkedList<String>();
+    protected HashMap<String, String> _attributeValue = new HashMap<String, String>();
 }
index 9e5f867..2fc754d 100644 (file)
@@ -107,12 +107,19 @@ public class XMLGenerator
         }\r
     }\r
 \r
+    public static String replaceWhiteSpaces(String tagName)\r
+    {\r
+        return tagName.replaceAll("\\s+", "_");\r
+    }\r
+\r
     public XMLGenerator startTag(String tagName, XMLAttribute attribute)\r
     {\r
         beforeStartTag();\r
 \r
+        String tag = replaceWhiteSpaces(tagName);\r
+\r
         _out.print("<");\r
-        _out.print(tagName);\r
+        _out.print(tag);\r
 \r
         if (attribute != null && attribute.length() > 0)\r
         {\r
@@ -122,7 +129,7 @@ public class XMLGenerator
         _out.print(">");\r
 \r
         _currentLevel++;\r
-        _tagStack.add(tagName);\r
+        _tagStack.add(tag);\r
         _prevOut = PreviousOutput.StartTag;\r
 \r
         return this;\r
diff --git a/src/test/java/org/xerial/silk/SilkUtilTest.java b/src/test/java/org/xerial/silk/SilkUtilTest.java
new file mode 100644 (file)
index 0000000..7f97364
--- /dev/null
@@ -0,0 +1,68 @@
+/*--------------------------------------------------------------------------\r
+ *  Copyright 2009 Taro L. Saito\r
+ *\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ *--------------------------------------------------------------------------*/\r
+//--------------------------------------\r
+// XerialJ\r
+//\r
+// SilkUtilTest.java\r
+// Since: 2009/02/14 5:57:08\r
+//\r
+// $URL$\r
+// $Author$\r
+//--------------------------------------\r
+package org.xerial.silk;\r
+\r
+import java.io.IOException;\r
+import java.io.StringReader;\r
+\r
+import org.junit.After;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.xerial.core.XerialException;\r
+import org.xerial.util.FileResource;\r
+import org.xerial.util.log.Logger;\r
+import org.xerial.util.xml.pullparser.PullParserUtil;\r
+import org.xmlpull.v1.XmlPullParser;\r
+import org.xmlpull.v1.XmlPullParserException;\r
+\r
+public class SilkUtilTest\r
+{\r
+    private static Logger _logger = Logger.getLogger(SilkUtilTest.class);\r
+\r
+    @Before\r
+    public void setUp() throws Exception\r
+    {}\r
+\r
+    @After\r
+    public void tearDown() throws Exception\r
+    {}\r
+\r
+    @Test\r
+    public void testToXML() throws IOException, XerialException, XmlPullParserException\r
+    {\r
+        String xml = SilkUtil.toXML(FileResource.find(SilkUtilTest.class, "small.silk"));\r
+        _logger.info(xml);\r
+\r
+        XmlPullParser pullParser = PullParserUtil.newParser(new StringReader(xml));\r
+\r
+        int event;\r
+        while ((event = pullParser.next()) != XmlPullParser.END_DOCUMENT)\r
+        {\r
+\r
+        }\r
+\r
+    }\r
+\r
+}\r