views:

436

answers:

2

In recent versions of the free and open source Eclipse IDE you can generate XML documents from DTD and XSD files. Right-click on a given *.dtd or *.xsd file and select "Generate -> XML File...". You can choose which root element to generate and whether optional attributes and elements should be generated.

Can i use this headless (without starting eclipse)?

Thank you

A: 

Hi chrsk. Did you see this question? It doesn't refer specifically to headless environments, but it's pretty similar.

One of the suggestions was the Sun XMLGenerator tool. I tried it and it worked like a charm.

Matt Solnit
Thank you. The Generator, is unfortunately unable to generate value for date datatype. Is it possible to generate the xml without data? So <element>string</element> is empty?
codedevour
+1  A: 

You can create a headless RCP application that contains only those plugins needed to do the actual generation. These are largely WTP plugins with a couple of the core plugins needed for managing extension points and such.

The RCP app can be run from the command line, and passed arguments for the schema to generate from and the output file name. It is missing much of the validation you might want in a production implementation, but shows you how it can be done. It also hardcodes the charset to UTF-8, you can extend the argument processing to make that an optional parameter or something.

The snippets below can be incorporated into a new headless RCP application. To create the RCP application, first create a new Plugin project:

  • Right-click->New->Other...->Plug-in Development->Plug-in Project, select Next
  • Enter a name for the project (e.g. name.seller.rich.xmlgen) and select Next
  • Uncheck This plug-in will make contributions to the UI and select Yes under Rich Client Application then click Finish
  • To add the required dependencies, double-click on META-INF/Manifest.MF and select the Dependencies tab of the editor add the following plugins to the Required Plug-ins section (click on Add... and add each one)
    • org.eclipse.core.runtime,
    • org.eclipse.core.resources;bundle-version="3.5.0",
    • org.eclipse.wst.common.uriresolver;bundle-version="1.1.301",
    • org.eclipse.wst.sse.core;bundle-version="1.1.400",
    • org.eclipse.wst.xml.core;bundle-version="1.1.400",
    • org.eclipse.wst.xml.ui;bundle-version="1.1.0",
    • org.eclipse.xsd;bundle-version="2.5.0",
    • com.ibm.icu;bundle-version="4.0.1",
    • org.eclipse.wst.xsd.core;bundle-version="1.1.401",
    • org.eclipse.wst.xsd.ui;bundle-version="1.2.204",
    • org.eclipse.emf.ecore;bundle-version="2.5.0"
  • In the project you should see an Application class, copy the Java content below into the start() method of the Application source (and the imports to the top of the file).

    import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.net.URI; import java.net.URL;

    import org.eclipse.core.internal.utils.FileUtil; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.ecore.plugin.EcorePlugin; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument; import org.eclipse.wst.xml.ui.internal.wizards.NewXMLGenerator;

    public Object start(IApplicationContext context) throws Exception { String[] args = Platform.getCommandLineArgs();

    String schemaFileName = args[0];// e.g. "C:\test\test.xsd"
    String xmlFileName = args[1];// e.g. "C:\test\test.xml"
    String rootName = args[2];//"myTestRoot";
    String charsetName = "UTF-8";
    
    
    try {
        //get the URI as a full URL path
        URI schemaUri = new File(schemaFileName).toURI();
        schemaFileName = schemaUri.toURL().toString();
    
    
    
    //TODO handle any errorInfo set into this array
    String[] errorInfo = new String[2];
    CMDocument cmDocument = NewXMLGenerator.createCMDocument(schemaFileName,
            errorInfo);
    NewXMLGenerator generator = new NewXMLGenerator(schemaFileName,
            cmDocument);
    
    
    generator.setRootElementName(rootName);
    
    
    ByteArrayOutputStream out = generator.createXMLDocument(xmlFileName,
            charsetName);
    
    
    //output the content to the file.
    File outFile = new File(xmlFileName);
    
    
    outFile.getParentFile().mkdirs();
    
    
    FileWriter writer = new FileWriter(outFile);
    
    
    writer.write(out.toString(charsetName));
    
    
    writer.flush();
    writer.close();
    
    } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return IApplication.EXIT_OK;

    }

To create a standalone application, you also need to create a Product Configuration.

  • Right-click->New->Other...->Plug-in Development->Product Configuration
  • Select the RCP plugin project
  • Enter config in the File Name: field and click Finish.
  • Enter some suitable values in the config.product editor ID, version and Name fields (they don't really matter as it is a headless product).
  • In Product Definition section, select New... button next to the Product: field, the default values should be fine (double check the Defining Plug-in is your RCP plug-in), select OK
  • Save the product

You now need to export the RCP application.

  • Right click on the project->Export...->Plug-in Development->Eclipse product
  • Enter a destination directory for the application, and select OK

You should now have a standalone application that you can invoke as you would any other application, passing command-line parameters to generate an XML file from a schema.

The expected parameters are, in order:

  • Fully-qualified path to the schema to generate from
  • Fully-qualified name of the file to create (parent directories will also be created).
  • The root element name (same as in the wizard, this is the name of the element you want to generate content below).


NOTE This process will only generate a file from a single schema, if your schema references other schemas it will currently fail. It would be possible to extend the process to take a properties file listing all the referenced schema locations, and resolve those as catalog contributions so the process can resolve the schemas. Some notes on how and why you'd do this below.
If I get the chance I'll look into implementing this and update my answer accordingly.


If you have, for example, a Spring schema you may want to include the various Spring namespace schema in your schema file. In Eclipse the Catalog contributions provide a means to map those schema IDs to the schema file location so it can be parsed. If you have plugins for them, they could be bundled with the application and define catalog contributions (see the help for pointers on contributing them).

If you don't have catalog contributions available, the process would instead define key-value pairs in the properties file to reference the schema locations on the drive.

Example contents:

 http://www.springframework.org/schema/beans=c:\\schema\\spring-beans.xsd
 http://www.springframework.org/schema/tool=c:\\schema\\spring-tool.xsd
Rich Seller
This is really great, thank you for your effort. I hope you like the bounty :)
codedevour
thanks very much and glad to help. Let me know if you have any issues with it. My only "problem" is that because you accepted early in the day, I will likely hit the rep limit before actually answering any questions. If it had been accepted towards the end of the day I could have the extra free points. Oh well at least I might go out for lunch today...
Rich Seller