XML Schema Explorer

Introduction

Now with the XML momentum, is very important to generate a valid XMLs against a XML Schema. The siblings order or the required elements can produce us a big headache. The first step is to review the schema definition, and there are a lot of tools that can help, but when we need to generate a XML file programatically, we need and API to solve this kind of problems.

My first try was generate a XML from the Schema definition, but with a Schema you can generate a lot of differents XMLs. The choices, sequences and the recursive parts make imposible to get a universal file. You can generate one of the posibilities, but not all.

Other way is to parse the .xsd file with xpath, but this would be a very complex task.

The natural way is to use the Schema definition to browse it and one APIs that can do it is Eclipse XSD.

Other API is XSOM XML Schema Object Model. I’ve not tested it, but if any of you have done, please send me your experiences.

If any of you know other APIs, please report me. I didn’t find other APIs.

First, i recoment to read the XML Schema specs at http://www.w3.org/TR/xmlschema-0/, it seems to be a hard task, but despite you can edit a .xsd file with high level tools like Eclipse WTP, always is a good idea make your first by hand. Reading the specs you have a complete review of all posibilities.

Make a .xsd file

Maybe you have to use an existing .xsd file, but it’s really interesting to create a new one. To make this task easier, i’m going to use eclipse + wtp.

create a simple .xsd file screencast

I this screencast i create a very simple schema file.

Ups, i’ve a mistake, i set string type to age and integer to name. Sorry

Parsing the schema file

I decided to use a helper class to isolate the schema related code from the other application code. The first step is to read the file and create a XSDSchema object. I used a method literally copied from a XSD API example that uses a DOM Element to acomplish this task:

private XSDSchema createSchema(Element element) {
 if (
  element.getLocalName().equals("schema") && 
  XSDConstants.isSchemaForSchemaNamespace(
     element.getNamespaceURI())) {
    XSDSchema xsdSchema = 
     XSDFactory.eINSTANCE.createXSDSchema();
    xsdSchema.setElement(element);
    return xsdSchema;
   } else {
    return null;
   }
}

So the constructor of my helper class was like this:

public SchemaHelper(String schemaFilename) 
  throws XSDException {

 this.schemaFilename = schemaFilename;
 DOMParser parser = new DOMParser();
 try {
  parser.parse(new InputSource(
  this.getClass().getResourceAsStream(
   "/"+schemaFilename)));
 } catch (Exception e) {
  throw new XSDException(e);
 }

 Document doc = parser.getDocument();
 xsd = createSchema((Element)doc.getFirstChild());
 logger.info("XSD: " + schemaFilename);
}

I read the file throw the class loader. I think it’s a good practice, later you can put your resources in the filesystem or in a java archive (.jar file) without any change in your source code.

The hard step: getting the results

In my helper class, the public method getSiblings() uses the parameter xpath to obtain the posible child elements in this xpath.

This parameter doen’t use the full syntax of xpath expressions. Only defines what elements you have chosen to use in the schema hierarchy. So, you can use:

/person

or

/person/name

Only accept element names an slashes, and you have to begin with a root element.

public List getSiblings(String xpath) {

 List list = getElementNames(toStack(xpath) , null);
 List output = new ArrayList();
		
 for(int i=0; i<list.size(); i++) {
			
  XSDElementDeclaration decl = 
   (XSDElementDeclaration)list.get(i);
  output.add(decl.getName());
 }
		
 return output;
}

the method toStack() parses the xpath to make a stack with the element names, it’ll be easier for me.

At this point we have to diferenciate between declaration and definition.

  • Definitions are related with types
  • Declarations are related with elements

The process seach declarations with the previous stack data (generated from simple xpath parameter), then obtain the definition (type) and last get the child element names:

  • create XSDSchema object (in contruction time, only one)
  • parse the xpath into a stack of element names (n times)
  • find the declaration of the top stack’s element
  • with the declaration, get the definition
  • if stack isn’t empty repeat the loop with the new top element
  • get the posible children element names of the declaration
  • return a list of names to user
private List getElementNames(Stack xpath, 
  XSDElementDeclaration declaration) {
 if (declaration == null) {
  declaration =  xsd.resolveElementDeclaration(
   (String)xpath.pop());
 } else {
  String elementName = (String)xpath.pop();
  XSDTypeDefinition typedef = getDefinition(declaration);
  declaration = getChildren(typedef, elementName);
 }
		
		
 if (!xpath.isEmpty()) {
  return getElementNames(xpath, declaration);
 } else {
  XSDTypeDefinition typedef = getDefinition(declaration);
  if (typedef instanceof XSDComplexTypeDefinition) {
   return getElementNames(
    (XSDComplexTypeDefinition)typedef);
  }
 }
		
 return new ArrayList();
	
}

Web interface (…and of course with DWR)

All this code is really cool, but is still hard to see the schema. A web interface is a good way to show this info, and of course, AJAX enable using DWR.

xsdexplorer

WIP…

sources comming soon.

No Comment

No comments yet

Leave a reply