[Odejava] new: XODE XML exporting!

Hi,

As a result of a request from Levent (who’s creating an Odejava visualiser), and several hours of work from me, one can now export XML data from an XODE tree.

The method is:


XODERoot.getDocument()

To print the XML text data, I use this:



import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

// ...

 try {
            OutputFormat format = new OutputFormat(document);
            format.setLineWidth(65);
            format.setIndenting(true);
            format.setIndent(2);
            XMLSerializer output = new XMLSerializer(System.out, format);
            output.serialize(document);
          }
          catch (IOException e) {
            System.err.println(e);
          }

The official “Truck” XODE example:


<?xml version="1.0" encoding="UTF-8"?>
<xode version="1.0r23" name="truck"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://tanksoftware.com/xode/1.0r23/xode.xsd">

<world>

        <space>


                <body name="chassis">
                        <transform>
                                <position x="-2.5" y="2.5" z="-3" />
                                <rotation>
                                        <euler x="0" y="90" z="0" aformat="degrees" />
                                </rotation>
                        </transform>

                        <geom name="chassisGeom">
                                <box
                                        sizex="5"
                                        sizey="6"
                                        sizez="7"
                                />
                        </geom>

                        <geom name="frontCabin">
                                <transform>
                                        <position x="0" y="0" z="4.5" />
                                </transform>
                                <box
                                        sizex="3"
                                        sizey="4"
                                        sizez="3"
                                />
                        </geom>


                        <body name="FrontLeft">
                                <transform>
                                        <position x="3" y="-3.5" z="-2.5" />
                                </transform>

                                <geom name="FrontLeftGeom">

                                        <sphere
                                                radius="1.5"
                                        />

                                </geom>

                                <joint name="FrontLeftJoint">

                                        <link1 body="chassis" />

                                        <hinge2>
                                                <axis x="0" y="1" z="0"
                                                        FMax="100"
                                                        LowStop="0"
                                                HiStop="0"
                                                />
                                                <axis x="0" y="0" z="1"
                                                        SuspensionERP="1"
                                                        SuspensionCFM="0.1"
                                                        FMax="500"
                                                />
                                        </hinge2>
                                </joint>

                                <mass><adjust density="0.2" /></mass>

                        </body>

                        <body name="FrontRight">
                                <transform>
                                        <position x="3" y="-3.5" z="2.5" />
                                </transform>


                                <geom name="FrontLeftGeom">

                                        <sphere
                                                radius="1.5"
                                        />

                                </geom>

                                <joint name="FrontRightJoint">

                                        <link1 body="chassis" />

                                        <hinge2>


                                                <axis x="0" y="1" z="0"
                                                        FMax="100"
                                                        LowStop="0"
                                                        HiStop="0"
                                                />
                                                <axis x="0" y="0" z="1"
                                                        SuspensionERP="1"
                                                        SuspensionCFM="0.1"
                                                        FMax="500"
                                                />


                                        </hinge2>
                                </joint>


                                <mass><adjust density="0.2" /></mass>

                        </body>

                        <body name="BackLeft">
                                <transform>
                                        <position x="-4" y="-3.5" z="-2.5" />
                                </transform>

                                <geom name="FrontLeftGeom">
                                        <sphere
                                                radius="1.5"
                                        />
                                </geom>

                                <joint name="BackLeftJoint">

                                        <link1 body="chassis" />

                                        <hinge2>
                                                <axis x="0" y="1" z="0"
                                                        FMax="100"
                                                        LowStop="0"
                                                        HiStop="0"
                                                />
                                                <axis x="0" y="0" z="1"
                                                        SuspensionERP="1"
                                                        SuspensionCFM="0.1"
                                                        FMax="500"
                                                />

                                        </hinge2>
                                </joint>


                                <mass><adjust density="0.2" /></mass>

                        </body>
                        <body name="BackRight">
                                <transform>
                                        <position x="-4" y="-3.5" z="2.5" />
                                </transform>

                                <geom name="BackRightGeom">
                                        <sphere
                                                radius="1.5"
                                        />
                                </geom>

                                <joint name="BackRightJoint">

                                        <link1 body="chassis" />

                                        <hinge2>

                                            <axis x="0" y="1" z="0"
                                                FMax="100"
                                                LowStop="0"
                                                HiStop="0"
                                            />
                                            <axis x="0" y="0" z="1"
                                                SuspensionERP="1"
                                                SuspensionCFM="0.1"
                                                FMax="500"

                                            />

                                        </hinge2>
                                </joint>

                                <mass><adjust density="0.2" /></mass>

                        </body>

                        <mass><adjust density="30" /></mass>

                </body>

        </space>
</world>
</xode>

yields the following after importing and exporting:


<?xml version="1.0" encoding="UTF-8"?>
<xode name="truck" version="1.0r23"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://tanksoftware.com/xode/1.0r23/xode.xsd">
  <world name="">
    <space name="">
      <body name="chassis">
        <transform>
          <euler x="0.0" y="1.5707964" z="0.0"/>
          <position x="-2.5" y="2.5" z="-3.0"/>
        </transform>
        <geom name="chassisGeom">
          <box sizex="5.0" sizey="6.0" sizez="7.0"/>
        </geom>
        <geom name="frontCabin">
          <transform>
            <position x="0.0" y="0.0" z="4.5"/>
          </transform>
          <box sizex="3.0" sizey="4.0" sizez="3.0"/>
        </geom>
        <body name="FrontLeft">
          <transform>
            <position x="3.0" y="-3.5" z="-2.5"/>
          </transform>
          <geom name="FrontLeftGeom">
            <sphere radius="1.5"/>
          </geom>
          <joint name="FrontLeftJoint">
            <link1 body="chassis"/>
            <hinge2>
              <anchor x="0.0" y="0.0" z="0.0"/>
              <axis FMax="100.0" HiStop="0.0" LowStop="0.0" x="0.0"
                y="1.0" z="0.0"/>
              <axis FMax="500.0" SuspensionCFM="0.1" SuspensionERP="1.0"
                x="0.0" y="0.0" z="1.0"/>
            </hinge2>
          </joint>
        </body>
        <body name="FrontRight">
          <transform>
            <position x="3.0" y="-3.5" z="2.5"/>
          </transform>
          <geom name="FrontLeftGeom">
            <sphere radius="1.5"/>
          </geom>
          <joint name="FrontRightJoint">
            <link1 body="chassis"/>
            <hinge2>
              <anchor x="0.0" y="0.0" z="0.0"/>
              <axis FMax="100.0" HiStop="0.0" LowStop="0.0" x="0.0"
                y="1.0" z="0.0"/>
              <axis FMax="500.0" SuspensionCFM="0.1" SuspensionERP="1.0"
                x="0.0" y="0.0" z="1.0"/>
            </hinge2>
          </joint>
        </body>
        <body name="BackLeft">
          <transform>
            <position x="-4.0" y="-3.5" z="-2.5"/>
          </transform>
          <geom name="FrontLeftGeom">
            <sphere radius="1.5"/>
          </geom>
          <joint name="BackLeftJoint">
            <link1 body="chassis"/>
            <hinge2>
              <anchor x="0.0" y="0.0" z="0.0"/>
              <axis FMax="100.0" HiStop="0.0" LowStop="0.0" x="0.0"
                y="1.0" z="0.0"/>
              <axis FMax="500.0" SuspensionCFM="0.1" SuspensionERP="1.0"
                x="0.0" y="0.0" z="1.0"/>
            </hinge2>
          </joint>
        </body>
        <body name="BackRight">
          <transform>
            <position x="-4.0" y="-3.5" z="2.5"/>
          </transform>
          <geom name="BackRightGeom">
            <sphere radius="1.5"/>
          </geom>
          <joint name="BackRightJoint">
            <link1 body="chassis"/>
            <hinge2>
              <anchor x="0.0" y="0.0" z="0.0"/>
              <axis FMax="100.0" HiStop="0.0" LowStop="0.0" x="0.0"
                y="1.0" z="0.0"/>
              <axis FMax="500.0" SuspensionCFM="0.1" SuspensionERP="1.0"
                x="0.0" y="0.0" z="1.0"/>
            </hinge2>
          </joint>
        </body>
      </body>
    </space>
  </world>
</xode>

Code is currently in CVS.

Cheers,

Will.

XODE Todo:

[] perhaps create an implementation of OutputFormat to output the XML in the standard XODE manner
[
] preserve angles specified in degrees
[] remove information about “absolute” transforms from the spec, it’s all relative now.
[
] implement unimplemented elements of body such as torque
[] add ability to add/remove child XODEObjects from XODEContainers to allow XODE trees to be constructed in java code (or JPhyzWiz)
[
] implement setters and getters for all attributes (plus, make private)

I can do most of that, but perhaps someone can tackle the first point? :slight_smile:

Cheers,

Will.

Hi,

Thanks again for adding this functionality.

It seems that adding a few lines of code will solve the first dot. :slight_smile: (no need to create an OutputFormat)

http://www.cafeconleche.org/books/xmljava/chapters/ch13s02.html

I will try it and post the results.

You’re welcome.

I meant to mention that book, it was extreemly useful to me: http://www.cafeconleche.org/books/xmljava/chapters/index.html

What I’d like to see are linebreaks between the attributes like so:


         <axis x="0" y="0" z="1"
           SuspensionERP="1"
           SuspensionCFM="0.1"
           FMax="500"
        /> 

Fairly low on the priority list though :slight_smile:

Let me know how it goes.

Cheers,

Will.

Here are related parts:

Indenting (false)
If true, then the serializer will add indents at each level and wrap lines that exceed the maximum line width. If false it won’t. The number of spaces to indent is set by the indent property, and the column to wrap at is set by the line width property.

public void setIndenting(boolean indenting);
public boolean getIndenting();

Indent (4)
The number of spaces to indent each level if indenting is true.

public void setIndent(int indent);
public int getIndent();

Line width (72)
The maximum number of characters in a line when indenting is true. Setting this to zero turns off line wrapping completely.

public void setLineWidth(int width);
public int getLineWidth();

So, we can set a line width, set indenting to true and give an indent value. The best way is this i think. I read “Creating DOMWriters” section too and it does not solve this problem either. (it just can select which nodes can be printed)

Example code:


format.setLineWidth(40);
format.setIndenting(true);
format.setIndent(6);

That is similar to what I did (see top of thread), but it doesn’t solve the problem of adding new lines after attributes, it only does elements. As I don’t think this isn’t a standard way of formatting XML data, I suspect we may have to roll our own.

Will.

Hi guys!

Consider using JAXB. It makes XML processing extremely easy. Have a look at this nice introduction:

http://java.sun.com/developer/technicalArticles/WebServices/jaxb/index.html

I’m using it for a project at work, and it works extremely well. As one of my colleagues said recently, it’s probably the only third-party product we’ve ever used that we haven’t complained about a single time yet :slight_smile:

Well, read the tutorial. You have my guarantee that it really does work as nicely as the article proposes - at least for XML parsing, I haven’t yet tried it for generating XML documents. However, it does have some output formatting capability, so I guess it’s fine for this too.

Kind regards,
Ole

Hi,

Too late :slight_smile: we have already implemented everything with Xerces.

Will.

Hi,

As planned before, i tried to implement “save/save as” in jphyswiz and test xode exporting feature.

Here are the problems i found:

  1. I need to clone XODEObjects for copy/pasting operations. When i clone a node and tried to add that node under a container (using addChild method) i get an XODEException, since setParent(…) method in XODEObject does not allow to to change parent if you have one already. So we need to modify something there. What are your thoughts?

  2. I looked at XODERoot but can not find getDocument method for exporting. Are you sure that you commited the changes?

  3. It seems that “adding ability to add/remove child XODEObjects from XODEContainers …” is in todo list. Isn’t this already implemented? This is also a very important requirement for jphyswiz now.

Levent.

Addition to second item:

When i used the document object obtained from XODEParser (xodeParser.getDocument()) added-child is not shown after serialization!

So i think Document object is not updated in any way, now.

[quote]Hi,

As planned before, i tried to implement “save/save as” in jphyswiz and test xode exporting feature.

Here are the problems i found:

  1. I need to clone XODEObjects for copy/pasting operations. When i clone a node and tried to add that node under a container (using addChild method) i get an XODEException, since setParent(…) method in XODEObject does not allow to to change parent if you have one already. So we need to modify something there. What are your thoughts?
    [/quote]
    EDIT: see my next post

It’s called “buildDocument” and it’s there, I got it in my CVS commit email.

if you can’t see it, do a “cvs update -d”

It is on the TODO list as it is not implemented. It is a trivial change though, and I realise this is very important for you (hence the reason it is on the TODO list). I will try to do it today.

UPDATED: see my next post :slight_smile:

Cheers,

Will.

[quote]Addition to second item:

When i used the document object obtained from XODEParser (xodeParser.getDocument()) added-child is not shown after serialization!

So i think Document object is not updated in any way, now.
[/quote]
The XML DOM objects are never updated. In fact the only reason they are even keep and not garbage collected is to aid in debugging (and the javadoc comment on the “Node” reaffirms this).

As this data is just unneeded junk most of the time, the node variable is marked ‘transient’, and the method scrapDOMObjectCache() exists.

My new XODERoot.buildDocument() can be used on an XODEObject whenever a new XML representation is required.

I believe serialization of XODE classes is possible without using XML (it is also possible with XML using buildDocument()).

Cheers,

Will.

Thanks for the quick replies and works.

[quote]… The clone method would have to exist in the XODEObject (or an extension of that class) so it is able to call the protected XODEObject.setParent method passing ‘null’ (the use of that method is explicitally not recommended unless one is very aware of the implications of using it, which in this case we are and it is the correct thing to do).
[/quote]
It seems that i should implement clone() method of XODEObject. I should add a method to XODEUtil class (i could not remember its name now and i do not have the source now) to clone objects using serialization (i gave the reference for alternative serialization method before) and use that method in XODEObject’s clone method plus setting the parent null.

Are these changes acceptable for you?

Levent.

I tested it.

After adding deepCopy(Object oldObj) method to DOMUtil class and implementing clone() method of XODEObject, it worked.

I am waiting for your ack. to commit the changes.


// returns a deep copy of an object
   static public Object deepCopy(Object oldObj) throws Exception
   {
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;
      try
      {
         ByteArrayOutputStream bos = 
               new ByteArrayOutputStream();
         oos = new ObjectOutputStream(bos);
         
         // serialize and pass the object
         oos.writeObject(oldObj);   
         oos.flush();               
         ByteArrayInputStream bin = 
               new ByteArrayInputStream(bos.toByteArray()); 
         ois = new ObjectInputStream(bin);                  
         
         // return the new object
         return ois.readObject(); 
      }
      catch(Exception e)
      {
         System.out.println("Exception in ObjectCloner = " + e);
         throw(e);
      }
      finally
      {
         oos.close();
         ois.close();
      }
   }


public Object clone() {

            XODEObject object = null;
            
            try {
                  object = (XODEObject)DOMUtil.deepCopy(this);            
            } catch(Exception e1) {
                  System.out.println(e1);
            }
            
            object.setParent(null);
            return object;
      
      }

Thanks.

Levent

ACK.

Good stuff ;D

Will.