XML help

So, this has nothing to do with jME; I am having a strange issue with XML reading (my XML skills aren't what they should be)



here's the XML


<?xml version="1.0"?>
<character>
  <name>Dwarf</name>
  <type>Player Character</type>
  <model>dwarf.ms3d</model>
  <physics_model>capsule</physics_model>
  <physics_size>4,6,4,8,24</physics_size>
  <shadows>false</shadows>
</character>



and here's the code to read it:


import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class XmlTest {

    public static void main( String[] args ) {
        new XmlTest();
    }

    public XmlTest() {
        String xmlPath = "dwarf.char"
        Document doc = getXmlDocument( xmlPath, true );

        NodeList nodeList = doc.getChildNodes();

        for( int i = 0; i < nodeList.getLength(); ++i ){
            printNodeList( nodeList.item( i ) );
        }
    }

    public void printNodeList( Node node ) {

        NodeList nodeList = node.getChildNodes();

        for( int i = 0; i < nodeList.getLength(); ++i ){
            Node tempNode = nodeList.item( i );

            System.out.println( tempNode.toString() );

            if( tempNode.hasChildNodes() ){
                printNodeList( tempNode.getNextSibling() );
            }
        }

    }

    public Document getXmlDocument( String filename, boolean validating ) {

        Document document = null;

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating( validating );

        try{
            DocumentBuilder builder = factory.newDocumentBuilder();
            File file = new File( filename );
            URL url = getURL( filename );
            if( url == null ){
                document = builder.parse( file );
            } else{
                document = builder.parse( url.openStream() );
            }
        } catch( Exception e ){
            log( e );
        }

        return document;

    }


}



And the output (which shows nothing but NULL values:

Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired.  Parser will use a default ErrorHandler to print the first 10  errors.  Please call the setErrorHandler method to fix this.
Error: URI = "null", Line = "2", : Document root element "character", must match DOCTYPE root "null".
Error: URI = "null", Line = "2", : Document is invalid: no grammar found.
[#text:
  ]
[name: null]
[#text:
  ]
[type: null]
[#text:
  ]
[model: null]
[#text:
  ]
[physics_model: null]
[#text:
  ]
[physics_size: null]
[#text:
  ]
[shadows: null]
[#text:
]


As always, any hints or suggestions are completely welcome.

I think you should first get the root element of that XML (the character TAG)



Here's the code I use:

public static Element getElement(URL XMLFile) {
      final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
      InputStream inputStream;
      try {
         inputStream = XMLFile.openStream();
         final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
         final Document document = docBuilder.parse(inputStream);
         return document.getDocumentElement();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (ParserConfigurationException e) {
         e.printStackTrace();
      } catch (SAXException e) {
         e.printStackTrace();
      }
      return null;
   }



You can also get my helper methods to parse attibutes as primitive types (and some more elaborate, such as Vector3f or Quaternions):

package gcore.config.xml.util;

import gcore.config.xml.XMLFileLoader;
import gcore.reflection.ReflectionHelper;

import java.net.URL;

import org.w3c.dom.Node;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;

public class XMLParseHelper {

   public static String getAttributeValue(final Node node, final String attributeName) {
      return getAttributeValue(node, attributeName, "");
   }

   public static String getAttributeValue(final Node node, final String attributeName, final String defaultValue) {
      final Node attNode = node.getAttributes().getNamedItem(attributeName);
      return attNode == null ? defaultValue : attNode.getNodeValue();
   }

   public static boolean getAtributeValueAsBoolean(Node node, String name) {
      String value = getAttributeValue(node, name, "false");
      return Boolean.parseBoolean(value);
   }

   public static URL getAttributeValueAsURL(final Node node, final String attributeName) {
      final String attributeValue = getAttributeValue(node, attributeName);
      return XMLParseHelper.class.getResource(attributeValue);
   }

   public static Float getAttributeValueAsFloat(final Node node, final String attributeName) {
      final String attributeValue = getAttributeValue(node, attributeName, "0");
      return Float.valueOf(attributeValue);
   }

   public static Integer getAttributeValueAsInteger(final Node node, final String attributeName) {
      final String attributeValue = getAttributeValue(node, attributeName, "0");
      return Integer.valueOf(attributeValue);
   }

   public static Vector3f getNodeAsVector3f(final Node vectorNode) {
      final Vector3f vector3f = new Vector3f();
      vector3f.setX(getAttributeValueAsFloat(vectorNode, "x"));
      vector3f.setY(getAttributeValueAsFloat(vectorNode, "y"));
      vector3f.setZ(getAttributeValueAsFloat(vectorNode, "z"));
      return vector3f;
   }
   
   public static Quaternion getNodeAsQuaternion(final Node quaternionNode) {
      final Quaternion quat = new Quaternion();
      quat.x = getAttributeValueAsFloat(quaternionNode, "x");
      quat.y = getAttributeValueAsFloat(quaternionNode, "y");
      quat.z = getAttributeValueAsFloat(quaternionNode, "z");
      quat.w = getAttributeValueAsFloat(quaternionNode, "w");
      return quat;
   }

   public static Class<?> getAttributeValueAsClass(final Node node, final String attributeName) {
      try {
         final String attributeValue = getAttributeValue(node, attributeName);
         if (attributeValue.endsWith("groovy"))
            return ReflectionHelper.getGroovyClass(attributeValue);
         else
            return Class.forName(attributeValue);
      } catch (final ClassNotFoundException e) {
         throw new RuntimeException(e);
      }
   }

   public static Node parseInclude(Node includeNode) {
      return XMLFileLoader.getElement(getAttributeValueAsURL(includeNode, "file"));
   }

   public static void parseIncludes(Node node) {
      for (int i = 0; i < node.getChildNodes().getLength(); i++) {
         Node internal = node.getChildNodes().item(i);
         if (internal.getNodeName().equals("include")) {
            node.appendChild(parseInclude(internal));
            node.removeChild(internal);
         }
      }
   }
   
   public static boolean isEmpty(String s){
      return (s == null || s.equals(""));
   }
}

Thanx perrick, yup I wasn't getting elements correctly.



Also, thanx a bunch for the helper methods, much appreciated. :slight_smile:





(I guess your the data-driven game guy here eh :))

I guess you've already seen this:

http://www.jmonkeyengine.com/jmeforum/index.php?topic=6980.0



Anyway, there's a link to the complete sources where you can take a look at these packages:



gcore.config - runtime representation of the GameObjects, GameStates and Components

gcore.config.xml - xml parsers to convert from XML to the above runtime rep.



I designed this runtime configuration, so I can later use it inside a (todo) level editor, or even autosave or something. Being easier to just parse/export xml…

Hello guys.



If you just plan to use XML as a format which you'll map to objects, and you are not going to use all the functionality (xpath, xsl or whatever), you can avoid a lot of extra work. Maybe you might want to have a look at:



Apache Jakarta Commons Configuration (http://commons.apache.org/configuration/). Reads properties and lists of properties from .properties, xml or a variety of sources.



Apache Jakarta Commons Betwixt (http://commons.apache.org/betwixt/index.html). Maps XML to JavaBeans.



Apache Jakarta Commons Digester (http://commons.apache.org/digester/). Rule based engine to digest XML and build in-memory object structures. Powerful but a bit difficult to master I guess.



I have personally used Commons Configuration and Commons Digester, and I they are really helpful in order to construct structures in memory or to read data from xml.



Hope it helps!

They are good pieces of software indeed, but I always tend to avoid the dependency in yet another framework. The XML parsing code I use (including the one here) took me about half an hour to design and type, so it wasn't really a waste of time.