Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jlibs.xml.xsd.XSInstance Maven / Gradle / Ivy
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.xml.xsd;
import jlibs.core.graph.*;
import jlibs.core.graph.navigators.FilteredTreeNavigator;
import jlibs.core.graph.sequences.DuplicateSequence;
import jlibs.core.graph.sequences.EmptySequence;
import jlibs.core.graph.sequences.IterableSequence;
import jlibs.core.graph.sequences.RepeatSequence;
import jlibs.core.graph.visitors.ReflectionVisitor;
import jlibs.core.graph.walkers.PreorderWalker;
import jlibs.core.io.IOUtil;
import jlibs.core.lang.ImpossibleException;
import jlibs.core.lang.OS;
import jlibs.core.net.URLUtil;
import jlibs.core.util.CollectionUtil;
import jlibs.core.util.RandomUtil;
import jlibs.xml.Namespaces;
import jlibs.xml.XMLUtil;
import jlibs.xml.sax.XMLDocument;
import jlibs.xml.xsd.display.XSDisplayFilter;
import org.apache.xerces.xs.*;
import org.xml.sax.SAXException;
import javax.xml.bind.DatatypeConverter;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamResult;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author Santhosh Kumar T
*/
@SuppressWarnings({"unchecked"})
public class XSInstance{
public int minimumElementsGenerated = 2;
public int maximumElementsGenerated = 2;
public int minimumListItemsGenerated = 2;
public int maximumListItemsGenerated = 2;
public int maximumRecursionDepth = 1;
// TRUE=always, FALSE=never, null=random
public Boolean generateOptionalElements = Boolean.TRUE;
public Boolean generateOptionalAttributes = Boolean.TRUE;
public Boolean generateFixedAttributes = Boolean.TRUE;
public Boolean generateDefaultAttributes = Boolean.TRUE;
public Boolean generateDefaultElementValues = Boolean.TRUE;
public boolean generateAllChoices = false;
// TRUE=always, FALSE=never, null=when_appropriate
public Boolean showContentModel = null;
private int generateRepeatCount(int minOccurs, int maxOccurs){
if(minOccurs==0 && maxOccurs==1) //optional case
return RandomUtil.randomBoolean(generateOptionalElements) ? 1 : 0;
if(maxOccurs==-1)
maxOccurs = Math.max(minOccurs, maximumElementsGenerated);
int min, max;
if(minimumElementsGenerated>maxOccurs || maximumElementsGenerated process(XSParticle particle){
XSTerm term = particle.getTerm();
if(term instanceof XSModelGroup){
XSModelGroup group = (XSModelGroup)term;
if(group.getCompositor()==XSModelGroup.COMPOSITOR_CHOICE){
XSObjectList particles = group.getParticles();
int count = particles.getLength();
if(!generateAllChoices && !particle.getMaxOccursUnbounded())
count = Math.min(count, particle.getMaxOccurs());
List list = new ArrayList(particles.getLength());
for(int i=0; i(super.process(particle), repeatCount);
}
protected Sequence process(XSModelGroup modelGroup){
switch(modelGroup.getCompositor()){
case XSModelGroup.COMPOSITOR_ALL :
XSObjectList particles = modelGroup.getParticles();
List list = new ArrayList(particles.getLength());
for(int i=0; i(list);
default:
return super.process(modelGroup);
}
}
protected Sequence process(XSElementDeclaration elem){
if(elem.getAbstract()){
XSObjectList substitutionGroup = xsModel.getSubstitutionGroup(elem);
if(substitutionGroup.getLength()==0)
return EmptySequence.getInstance();
int rand = RandomUtil.random(0, substitutionGroup.getLength() - 1);
return new DuplicateSequence(substitutionGroup.item(rand));
}
if(elem.getTypeDefinition() instanceof XSComplexTypeDefinition){
XSComplexTypeDefinition complexType = (XSComplexTypeDefinition)elem.getTypeDefinition();
if(complexType.getAbstract()){
XSTypeDefinition subType = null;
if(sampleValueGenerator!=null)
subType = sampleValueGenerator.selectSubType(elem);
if(subType==null){
List subTypes = XSUtil.getSubTypes(xsModel, complexType);
if(subTypes.isEmpty())
return EmptySequence.getInstance();
int rand = RandomUtil.random(0, subTypes.size() - 1);
subType = subTypes.get(rand);
}
return new DuplicateSequence(subType);
}
}
return new DuplicateSequence(elem.getTypeDefinition());
}
}
private class XSSampleVisitor extends ReflectionVisitor>{
private XMLDocument doc;
private String xsiSchemaLocation;
private String xsiNoNamespaceSchemaLocation;
private XSSampleVisitor(XMLDocument doc, String xsiSchemaLocation, String xsiNoNamespaceSchemaLocation){
this.doc = doc;
this.xsiSchemaLocation = xsiSchemaLocation;
this.xsiNoNamespaceSchemaLocation = xsiNoNamespaceSchemaLocation;
}
private void addXSILocations() throws SAXException{
if(doc.getDepth()==1){
if(xsiSchemaLocation!=null)
doc.addAttribute(Namespaces.URI_XSI, "schemaLocation", xsiSchemaLocation);
if(xsiNoNamespaceSchemaLocation!=null)
doc.addAttribute(Namespaces.URI_XSI, "noNamespaceSchemaLocation", xsiNoNamespaceSchemaLocation);
}
}
@Override
protected Processor getDefault(Object elem){
return null;
}
protected Processor process(XSElementDeclaration elem){
return elemProcessor;
}
protected Processor process(XSWildcard wildcard){
return wildcardProcessor;
}
protected Processor process(XSComplexTypeDefinition complexType){
return complexTypeProcessor;
}
protected Processor process(XSAttributeUse attr){
return attrProcessor;
}
private Processor elemProcessor = new Processor(){
private boolean isRecursionDepthCrossed(XSElementDeclaration elem, Path path){
if(path.getRecursionDepth()>maximumRecursionDepth)
return true;
int typeRecursionDepth = -1;
while(path!=null){
if(path.getElement()==elem.getTypeDefinition())
typeRecursionDepth++;
path = path.getParentPath();
}
return typeRecursionDepth>maximumRecursionDepth;
};
@Override
public boolean preProcess(XSElementDeclaration elem, Path path){
if(isRecursionDepthCrossed(elem, path))
return false;
try{
if(!Boolean.FALSE.equals(showContentModel) && elem.getTypeDefinition() instanceof XSComplexTypeDefinition){
XSComplexTypeDefinition complexType = (XSComplexTypeDefinition)elem.getTypeDefinition();
StringBuilder contentModel = new StringBuilder();
XSObjectList attributeUses = complexType.getAttributeUses();
if(!attributeUses.isEmpty()){
contentModel.append("@(");
for(int i=0; i0)
contentModel.append(", ");
contentModel.append(XMLUtil.getQName(XSUtil.getQName(attrUse, doc.getNamespaceSupport())));
if(!attrUse.getRequired())
contentModel.append('?');
}
contentModel.append(")");
}
switch(complexType.getContentType()){
case XSComplexTypeDefinition.CONTENTTYPE_ELEMENT:
case XSComplexTypeDefinition.CONTENTTYPE_MIXED:
if(contentModel.length()>0)
contentModel.append(" ");
contentModel.append(new XSContentModel().toString(complexType, doc));
}
if(contentModel.length()>0){
boolean addComment = false;
if(Boolean.TRUE.equals(showContentModel))
addComment = true;
else{
for(char ch: "?*+|;[".toCharArray()){
if(contentModel.indexOf(String.valueOf(ch))!=-1){
addComment = true;
break;
}
}
}
if(addComment)
addComment(path, contentModel.toString());
}
}
doc.startElement(elem.getNamespace(), elem.getName());
addXSILocations();
return true;
}catch(SAXException ex){
throw new ImpossibleException(ex);
}
}
private void addComment(Path path, String comment) throws SAXException{
int depth = 0;
while(true){
path = path.getParentPath(XSElementDeclaration.class);
if(path!=null)
depth++;
else
break;
}
doc.addText("\n");
for(int i=depth; i>0; i--)
doc.addText(" ");
doc.addComment(comment);
doc.addText("\n");
for(int i=depth; i>0; i--)
doc.addText(" ");
}
@Override
public void postProcess(XSElementDeclaration elem, Path path){
if(isRecursionDepthCrossed(elem, path))
return;
try{
switch(elem.getConstraintType()){
case XSConstants.VC_FIXED:
doc.addText(elem.getValueConstraintValue().getNormalizedValue());
break;
case XSConstants.VC_DEFAULT:
if(RandomUtil.randomBoolean(generateDefaultElementValues)){
doc.addText(elem.getValueConstraintValue().getNormalizedValue());
break;
}
default:
XSSimpleTypeDefinition simpleType = null;
if(elem.getTypeDefinition().getTypeCategory()==XSTypeDefinition.SIMPLE_TYPE)
simpleType = (XSSimpleTypeDefinition)elem.getTypeDefinition();
else{
XSComplexTypeDefinition complexType = (XSComplexTypeDefinition)elem.getTypeDefinition();
if(complexType.getContentType()==XSComplexTypeDefinition.CONTENTTYPE_SIMPLE)
simpleType = complexType.getSimpleType();
}
if(simpleType!=null){
String sampleValue = null;
if(sampleValueGenerator!=null)
sampleValue = sampleValueGenerator.generateSampleValue(elem, simpleType);
if(sampleValue==null)
sampleValue = generateSampleValue(simpleType, elem.getName());
doc.addText(sampleValue);
}
}
doc.endElement();
}catch(SAXException ex){
throw new ImpossibleException(ex);
}
}
};
private Processor attrProcessor = new Processor(){
@Override
public boolean preProcess(XSAttributeUse attr, Path path){
try{
XSAttributeDeclaration decl = attr.getAttrDeclaration();
String sampleValue = null;
switch(attr.getConstraintType()){
case XSConstants.VC_FIXED:
if(RandomUtil.randomBoolean(generateFixedAttributes))
sampleValue = attr.getValueConstraintValue().getNormalizedValue();
break;
case XSConstants.VC_DEFAULT:
if(RandomUtil.randomBoolean(generateDefaultAttributes))
sampleValue = attr.getValueConstraintValue().getNormalizedValue();
break;
default:
if(attr.getRequired() || RandomUtil.randomBoolean(generateOptionalAttributes)){
if(sampleValueGenerator!=null)
sampleValue = sampleValueGenerator.generateSampleValue(decl, decl.getTypeDefinition());
if(sampleValue==null)
sampleValue = generateSampleValue(decl.getTypeDefinition(), decl.getName());
}
}
if(sampleValue!=null)
doc.addAttribute(decl.getNamespace(), decl.getName(), sampleValue);
return false;
}catch(SAXException ex){
throw new ImpossibleException(ex);
}
}
@Override
public void postProcess(XSAttributeUse elem, Path path){}
};
private Processor complexTypeProcessor = new Processor(){
@Override
public boolean preProcess(XSComplexTypeDefinition complexType, Path path){
try{
XSElementDeclaration elem = (XSElementDeclaration)path.getParentPath().getElement();
XSComplexTypeDefinition elemType = (XSComplexTypeDefinition)elem.getTypeDefinition();
if(elemType.getAbstract())
doc.addAttribute(Namespaces.URI_XSI, "type", doc.toQName(complexType.getNamespace(), complexType.getName()));
return true;
}catch(SAXException ex){
throw new ImpossibleException(ex);
}
}
@Override
public void postProcess(XSComplexTypeDefinition complexType, Path path){}
};
private Processor wildcardProcessor = new Processor(){
@Override
public boolean preProcess(XSWildcard wildcard, Path path){
if(wildcard.getProcessContents()==XSWildcard.PC_STRICT)
return true;
try{
String uri;
switch(wildcard.getConstraintType()){
case XSWildcard.NSCONSTRAINT_ANY:
uri = "anyNS";
break;
case XSWildcard.NSCONSTRAINT_LIST:
StringList list = wildcard.getNsConstraintList();
int rand = RandomUtil.random(0, list.getLength()-1);
uri = list.item(rand);
if(uri==null)
uri = ""; // returns nsConstraintList with null
break;
case XSWildcard.NSCONSTRAINT_NOT:
list = wildcard.getNsConstraintList();
List namespaces = new ArrayList();
for(int i=0; i counters = new HashMap();
private static final String XSD_DATE_FORMAT = "yyyy-MM-dd";
private static final String XSD_TIME_FORMAT = "HH:mm:ss";
private String generateSampleValue(XSSimpleTypeDefinition simpleType, String hint){
if(simpleType.getBuiltInKind()==XSConstants.LIST_DT){
XSSimpleTypeDefinition itemType = simpleType.getItemType();
int len;
XSFacet facet = getFacet(itemType, XSSimpleTypeDefinition.FACET_LENGTH);
if(facet!=null)
len = Integer.parseInt(facet.getLexicalFacetValue());
else{
int minOccurs = 0;
facet = getFacet(itemType, XSSimpleTypeDefinition.FACET_MINLENGTH);
if(facet!=null)
minOccurs = Integer.parseInt(facet.getLexicalFacetValue());
int maxOccurs = -1;
facet = getFacet(itemType, XSSimpleTypeDefinition.FACET_MAXLENGTH);
if(facet!=null)
maxOccurs = Integer.parseInt(facet.getLexicalFacetValue());
if(maxOccurs==-1)
maxOccurs = Math.max(minOccurs, maximumListItemsGenerated);
int min, max;
if(minimumListItemsGenerated>maxOccurs || maximumListItemsGenerated enums = XSUtil.getEnumeratedValues(itemType);
if(enums.isEmpty()){
StringBuilder buff = new StringBuilder();
while(len>0){
buff.append(" ");
buff.append(generateSampleValue(itemType, hint));
len--;
}
return buff.toString().trim();
}else{
while(enums.size()(enums));
Collections.shuffle(enums);
StringBuilder buff = new StringBuilder();
while(len>0){
buff.append(" ");
buff.append(enums.remove(0));
len--;
}
return buff.toString().trim();
}
}else if(simpleType.getMemberTypes().getLength()>0){
XSObjectList members = simpleType.getMemberTypes();
int rand = RandomUtil.random(0, members.getLength()-1);
return generateSampleValue((XSSimpleTypeDefinition)members.item(rand), hint);
}
List enums = XSUtil.getEnumeratedValues(simpleType);
if(!enums.isEmpty())
return enums.get(RandomUtil.random(0, enums.size()-1));
XSSimpleTypeDefinition builtInType = simpleType;
while(!Namespaces.URI_XSD.equals(builtInType.getNamespace()))
builtInType = (XSSimpleTypeDefinition)builtInType.getBaseType();
String name = builtInType.getName().toLowerCase();
if("boolean".equals(name))
return RandomUtil.randomBoolean() ? "true" : "false";
if("double".equals(name)
|| "decimal".equals(name)
|| "float".equals(name)
|| name.endsWith("integer")
|| name.endsWith("int")
|| name.endsWith("long")
|| name.endsWith("short")
|| name.endsWith("byte"))
return randomNumber(simpleType, name);
if("date".equals(name))
return new SimpleDateFormat(XSD_DATE_FORMAT).format(new Date());
if("time".equals(name))
return new SimpleDateFormat(XSD_TIME_FORMAT).format(new Date());
if("datetime".equals(name)){
Date date = new Date();
return new SimpleDateFormat(XSD_DATE_FORMAT).format(date)+'T'+new SimpleDateFormat(XSD_TIME_FORMAT).format(date);
}else{
Integer count = counters.get(hint);
count = count==null ? 1 : ++count;
counters.put(hint, count);
String countStr = count.toString();
XSFacet lengthFacet = getFacet(simpleType, XSSimpleTypeDefinition.FACET_LENGTH);
XSFacet facet = getFacet(simpleType, XSSimpleTypeDefinition.FACET_MINLENGTH);
if(facet==null)
facet = lengthFacet;
if(facet!=null){
int len = Integer.parseInt(facet.getLexicalFacetValue());
len -= hint.length();
len -= countStr.length();
if(len>0){
char ch[] = new char[len];
Arrays.fill(ch, '_');
hint += new String(ch);
}
}
facet = getFacet(simpleType, XSSimpleTypeDefinition.FACET_MAXLENGTH);
if(facet==null)
facet = lengthFacet;
if(facet!=null){
int maxLen = Integer.parseInt(facet.getLexicalFacetValue());
int len = maxLen;
len = hint.length() + countStr.length() - len;
if(len>0){
if(hint.length()>len)
hint = hint.substring(0, hint.length()-len);
else{
hint = hint.substring(0, maxLen);
countStr = "";
}
}
}
String value = hint+countStr;
if("base64binary".equals(name))
return DatatypeConverter.printBase64Binary(value.getBytes(IOUtil.UTF_8));
else
return value;
}
}
private XSFacet getFacet(XSSimpleTypeDefinition simpleType, int kind){
XSObjectList facets = simpleType.getFacets();
for(int i=0; i=0?fractionDigits:3)+"f", (Double)randomNumber);
else
str = String.valueOf(randomNumber);
String number, fraction;
int dot = str.indexOf(".");
if(dot==-1){
number = str;
fraction = "";
}else{
number = str.substring(0, dot);
fraction = str.substring(dot+1);
}
boolean negative = false;
if(number.startsWith("-")){
negative = true;
number = number.substring(1);
}
if(totalDigits>=0){
if(number.length()>totalDigits)
number = number.substring(0, totalDigits);
}
if(fractionDigits>=0){
if(fraction.length()>fractionDigits)
fraction = fraction.substring(0, fractionDigits);
}
str = negative ? "-" : "";
str += number;
if(fraction.length()>0)
str += '.' + fraction;
return str;
}
}
public void loadOptions(Properties options){
String value = options.getProperty("minimumElementsGenerated");
if(value!=null)
minimumElementsGenerated = Integer.parseInt(value);
value = options.getProperty("maximumElementsGenerated");
if(value!=null)
maximumElementsGenerated = Integer.parseInt(value);
value = options.getProperty("minimumListItemsGenerated");
if(value!=null)
minimumListItemsGenerated = Integer.parseInt(value);
value = options.getProperty("maximumListItemsGenerated");
if(value!=null)
maximumListItemsGenerated = Integer.parseInt(value);
value = options.getProperty("maximumRecursionDepth");
if(value!=null)
maximumRecursionDepth = Integer.parseInt(value);
value = options.getProperty("generateOptionalElements");
if(value!=null)
generateOptionalElements = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
value = options.getProperty("generateOptionalAttributes");
if(value!=null)
generateOptionalAttributes = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
value = options.getProperty("generateFixedAttributes");
if(value!=null)
generateFixedAttributes = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
value = options.getProperty("generateDefaultAttributes");
if(value!=null)
generateDefaultAttributes = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
value = options.getProperty("generateDefaultElementValues");
if(value!=null)
generateDefaultElementValues = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
value = options.getProperty("generateAllChoices");
if(value!=null)
generateAllChoices = Boolean.parseBoolean(value);
value = options.getProperty("showContentModel");
if(value!=null)
showContentModel = "always".equals(value) ? Boolean.TRUE : ("never".equals(value) ? Boolean.FALSE : null);
}
public SampleValueGenerator sampleValueGenerator;
public static interface SampleValueGenerator{
public String generateSampleValue(XSElementDeclaration element, XSSimpleTypeDefinition simpleType);
public String generateSampleValue(XSAttributeDeclaration attribute, XSSimpleTypeDefinition simpleType);
public XSTypeDefinition selectSubType(XSElementDeclaration element);
}
public static void main(String[] args) throws Exception{
if(args.length==0){
System.err.println("Usage:");
System.err.println("\txsd-instance."+(OS.get().isWindows()?"bat":"sh")+" [root-element]");
System.err.println("Example:");
System.err.println("\txsd-instance."+(OS.get().isWindows()?"bat":"sh")+" purchase-order.xsd {http://jlibs.org}PurchaseOrder");
System.exit(1);
}
XSModel xsModel = new XSParser().parse(args[0]);
QName rootElement = null;
if(args.length>1)
rootElement = QName.valueOf(args[1]);
else{
List elements = XSUtil.guessRootElements(xsModel);
if(elements.size()==0){
System.err.println("no elements found in given xml schema");
System.exit(1);
}else if(elements.size()==1){
XSElementDeclaration elem = elements.get(0);
rootElement = XSUtil.getQName(elem);
}else{
int i = 1;
for(XSElementDeclaration elem: elements)
System.err.println(i++ +": "+XSUtil.getQName(elem));
System.err.print("Select Root Element: ");
String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
XSElementDeclaration elem = elements.get(Integer.parseInt(line)-1);
rootElement = XSUtil.getQName(elem);
}
}
XSInstance xsInstance = new XSInstance();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("xsd-instance.properties");
if(is!=null)
xsInstance.loadOptions(CollectionUtil.readProperties(is, null));
XMLDocument xml = new XMLDocument(new StreamResult(System.out), true, 4, null);
XSUtil.suggestNamespacePrefixes(URLUtil.toURL(args[0]), xml);
xsInstance.generate(xsModel, rootElement, xml);
System.out.println();
}
}