1

In an application I'm working on I need to generate sample data (XML instance) from XSD. I have XSD in the form of a String and need to generate respective XML as String again.

For example consider the below XSD

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Employee">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="name"/>
        <xs:element type="xs:byte" name="age"/>
        <xs:element type="xs:string" name="role"/>
        <xs:element type="xs:string" name="gender"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

I want to generate

<Employee>
  <name>string</name>
  <age>2</age>
  <role>string</role>
  <gender>string</gender>
</Employee>

After searching for a while came across various online tools which does this, but I want to be able to achieve it using Java. Also there are IDEs like Eclipse, Netbeans, IntelliJ which are able to achieve the desired functionality, except that they rely on XSD to be given as a File.

After bit of searching around seems like most of these use Apache XMLBeans.

I tried following the installation guide and setup all the environment variables mentioned like below

export XMLBEANS_HOME=/home/user/Programs/xmlbeans-3.1.0
PATH=$PATH:$XMLBEANS_HOME/bin
export CLASSPATH=$XMLBEANS_HOME/lib/xmlbeans-3.1.0.jar:$CLASSPATH
export XMLBEANS_LIB=/home/user/Programs/xmlbeans-3.1.0/lib/xmlbeans-3.1.0.jar

After all this if I run the command given below

./xsd2inst ../../Schema.xsd

I get error

Error: Could not find or load main class org.apache.xmlbeans.impl.xsd2inst.SchemaInstanceGenerator

Questions:

  1. What can I do to fix this error?
  2. If I get this working I can probably invoke the this command from a java process after writing XSD string in to a file and pass that as an argument to the command just like I have shown above. But I don't think this is an elegant solution, Is there any other way to accomplish what I have mentioned?

Note:

  1. I cannot make use of any commercial products/libraries.
  2. I'm aware of using JAXB, but that will require me to create a POJO for the types that I want to generate data for which isn't something that I can do since XSD data is dynamic and I cannot reuse those POJOs even if I create it.
4
  • Just out of interest, what is causing you to believe that XMLBeans is still retired? Is there something on the site that is unclear? Or are you seeing something elsewhere on the internet. If it is a problem with the XMLBeans website that is causing confusion I can get that fixed. If it is something elsewhere on the internet (or even here on SO), let me reassure you that XMLBeans is being actively developed as a sub-project of the apache POI project, and can be used in a stand-alone manner without including apache POI. Commented Aug 12, 2019 at 13:55
  • I don't know if its my interpretation, when I read the line "The Apache POI project has unretired the XMLBeans codebase and is maintaining it as a sub-project. Until now the XMLBeans codebase was held in the Apache Attic where former Apache projects are kept for the public good." I felt its a retired project, but then Apache POI has a unretired version of it which can be used. May be I should remove my mentioning about it in the question just to avoid any confusion, if that's okay I will go ahead and do that. Commented Aug 13, 2019 at 4:35
  • XMLBeans was indeed in the attic, but has been out of the attic for over a year now, and is being actively maintained. Commented Aug 13, 2019 at 12:30
  • Thank you for the update. I have removed those lines from question to avoid confusion. Commented Aug 13, 2019 at 14:10

1 Answer 1

1

After digging in a little bit, realised the environment variable value for XMLBEANS_LIB is wrongly set. The XMLBEANS_LIB expects to be pointed to the lib directory of the XML Beans distribution not to xmlbeans-3.1.0.jar. So the correct value for that is

 export XMLBEANS_LIB=/home/user/Programs/xmlbeans-3.1.0/lib

I was able to generate the XMLInstance (as a String) using XSD ( given as String) using the below code.

import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.xsd2inst.SampleXmlUtil;
import org.apache.xmlbeans.impl.xsd2inst.SchemaInstanceGenerator;

import java.util.ArrayList;
import java.util.List;

public class XmlInstanceGeneratorImpl {
  private static final Logger logger = LogManager.getLogger(XmlInstanceGeneratorImpl.class);

  /**
   * Specifies if network downloads are enabled for imports and includes.
   * Default value is {@code false}
   */
  private static final boolean ENABLE_NETWORK_DOWNLOADS = false;

  /**
   * disable particle valid (restriction) rule
   * Default value is {@code false}
   */
  private static final boolean NO_PVR = false;

  /**
   * disable unique particle attribution rule.
   * Default value is {@code false}
   */
  private static final boolean NO_UPA = false;


  public String generateXmlInstance(String xsdAsString, String elementToGenerate){
    return generateXmlInstance(xsdAsString, elementToGenerate, ENABLE_NETWORK_DOWNLOADS, NO_PVR, NO_UPA);
  }


  public String generateXmlInstance(String xsAsString, String elementToGenerate, boolean enableDownloads,
                                    boolean noPvr, boolean noUpa){
    List<XmlObject> schemaXmlObjects = new ArrayList<>();
    try {
      schemaXmlObjects.add(XmlObject.Factory.parse(xsAsString));
    } catch (XmlException e) {
      logger.error("Error Occured while Parsing Schema",e);
    }
    XmlObject[] xmlObjects = schemaXmlObjects.toArray(new XmlObject[1]);
    SchemaInstanceGenerator.Xsd2InstOptions options = new SchemaInstanceGenerator.Xsd2InstOptions();
    options.setNetworkDownloads(enableDownloads);
    options.setNopvr(noPvr);
    options.setNoupa(noUpa);
    return xsd2inst(xmlObjects, elementToGenerate, options);
  }

  private String xsd2inst(XmlObject[] schemas, String rootName, SchemaInstanceGenerator.Xsd2InstOptions options){
    SchemaTypeSystem schemaTypeSystem = null;
    if (schemas.length > 0) {
      XmlOptions compileOptions = new XmlOptions();
      if (options.isNetworkDownloads())
        compileOptions.setCompileDownloadUrls();
      if (options.isNopvr())
        compileOptions.setCompileNoPvrRule();
      if (options.isNoupa())
        compileOptions.setCompileNoUpaRule();
      try {
        schemaTypeSystem = XmlBeans.compileXsd(schemas, XmlBeans.getBuiltinTypeSystem(), compileOptions);
      } catch (XmlException e) {
        logger.error("Error occurred while compiling XSD",e);
      }
    }
    if (schemaTypeSystem == null) {
      throw new RuntimeException("No Schemas to process.");
    }

    SchemaType[] globalElements = schemaTypeSystem.documentTypes();
    SchemaType elem = null;
    for (SchemaType globalElement : globalElements) {
      if (rootName.equals(globalElement.getDocumentElementName().getLocalPart())) {
        elem = globalElement;
        break;
      }
    }
    if (elem == null) {
      throw new RuntimeException("Could not find a global element with name \"" + rootName + "\"");
    }
    // Now generate it and return the result
    return SampleXmlUtil.createSampleForType(elem);
  }
}

Sign up to request clarification or add additional context in comments.

1 Comment

This looks like an interesting approach. Do you have any sample implementation?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.