Skip to content

Commit

Permalink
Make SampleXmlBuilder use qualified names more intelligently
Browse files Browse the repository at this point in the history
  • Loading branch information
jhannes committed Aug 31, 2017
1 parent 6130e7e commit 74d7107
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 65 deletions.
9 changes: 6 additions & 3 deletions src/main/java/org/eaxy/Element.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public List<Namespace> getNamespaces() {

public Namespace getNamespace(String prefix) {
for (Namespace namespace : namespaces) {
if (prefix.equals(namespace.getPrefix())) {
if (Objects.equals(prefix, namespace.getPrefix())) {
return namespace;
}
}
Expand Down Expand Up @@ -183,9 +183,12 @@ Element namespace(Namespace namespace) {
if (namespace.getUri() == null) {
throw new IllegalArgumentException("Invalid namespace " + namespace);
}
if (!namespaces.contains(namespace)) {
namespaces.add(namespace);
for (Namespace existingNamespace : namespaces) {
if (Objects.equals(namespace.getPrefix(), existingNamespace.getPrefix())) {
return this;
}
}
namespaces.add(namespace);
return this;
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/eaxy/Xml.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public Node copy() {
}
}

public static Element el(QualifiedName name, Content... contents) {
return new Element(name, contents);
}

public static Element el(String tagName, Content... contents) {
return Namespace.NO_NAMESPACE.el(tagName, contents);
}
Expand Down
160 changes: 98 additions & 62 deletions src/main/java/org/eaxy/experimental/SampleXmlBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.eaxy.Element;
import org.eaxy.ElementSet;
import org.eaxy.Namespace;
import org.eaxy.QualifiedName;
import org.eaxy.Xml;

public class SampleXmlBuilder {
Expand All @@ -39,6 +40,10 @@ public SampleXmlBuilder(URL resource, String nsPrefix) throws IOException {
}

public Element createRandomElement(String elementName) {
return createRandomElement(targetNamespace().name(elementName));
}

private Element createRandomElement(QualifiedName elementName) {
Element elementDefinition = elementDefinition(elementName);
if (elementDefinition.type() != null) {
return createElement(elementName, complexType(elementDefinition.type()));
Expand All @@ -48,14 +53,27 @@ public Element createRandomElement(String elementName) {
}
}

private Element createElement(String fullElementName, Element complexType) {
String[] parts = fullElementName.split(":");
String name = parts.length > 1 ? parts[1] : parts[0];
Element resultElement = targetNamespace().el(name);
private Element createElement(QualifiedName elementName, Element complexType) {
Element resultElement = Xml.el(elementName);
populateComplexType(complexType, resultElement);
return resultElement;
}

private QualifiedName qualifiedName(String fullElementName) {
if (fullElementName == null) {
return null;
}
String[] parts = fullElementName.split(":");
if (parts.length == 1) {
// TODO: Find the correct namespace by looking at namespace declarations of schema
// Namespace namespace = schemaDoc.getRootElement().getNamespace(null);
return targetNamespace().name(fullElementName);
} else {
Namespace namespace = schemaDoc.getRootElement().getNamespace(parts[0]);
return namespace.name(parts[1]);
}
}

private Element populateComplexType(Element complexType, Element resultElement) {
if (complexType.find("complexContent").isPresent()) {
Element extension = complexType.find("complexContent", "extension").single();
Expand All @@ -76,41 +94,25 @@ private void populateAttributes(Element resultElement, Element complexType) {
} else if (!"required".equals(attrDef.attr("use")) && !full && chance(.50)) {
continue;
}
String typeDef = attrDef.attr("ref");
if (typeDef != null) {
Element attrTypeDef = attributeDefinition(typeDef);

ElementSet enumerations = attrTypeDef.find("simpleType", "restriction", "enumeration");
if (enumerations.isPresent()) {
resultElement
.attr(targetNamespace().attr(attrTypeDef.name(), pickOne(enumerations.attrs("value"))));
}
} else if (isXsdType(attrDef.type())) {
resultElement.attr(attrDef.name(), randomData(attrDef));
QualifiedName type = qualifiedName(attrDef.type());
if (type == null) {
Element attrTypeDef = attributeDefinition(attrDef.attr("ref"));
Element simpleType = attrTypeDef.find("simpleType").single();
resultElement.attr(targetNamespace().attr(attrTypeDef.name(), randomAttributeText(attrTypeDef.name(), simpleType)));
} else if (isXsdType(type)) {
resultElement.attr(attrDef.name(), randomAttributeText(attrDef.name(), attrDef));
} else {
String typeNameFull = attrDef.type();
String[] nameParts = typeNameFull.split(":");
String typeName = nameParts.length > 1 ? nameParts[1] : typeNameFull;
Element simpleType = schemaDoc.find("simpleType[name=" + typeName + "]").single();

String baseType = simpleType.find("restriction").single().attr("base");
if (baseType.matches(xsNamespace.name("string").print())) {
resultElement.attr(attrDef.name(), "123-AB");
} else {
throw new RuntimeException("Don't know what to do with " + baseType);
}
Element simpleType = schemaDoc.find("simpleType[name=" + type.getName() + "]").single();
resultElement.attr(attrDef.name(), randomAttributeText(attrDef.name(), simpleType));
}
}
}


private boolean chance(double p) {
return random.nextDouble() < p;
}

private Instant randomDateTime() {
return ZonedDateTime.now().minusDays(100).plusMinutes(new Random().nextInt(200 * 24 * 60)).toInstant();
}

private void appendSequence(Element resultElement, Element complexType) {
for (Element seqMemberDef : complexType.find("sequence", "*")) {
appendChildElements(resultElement, seqMemberDef);
Expand All @@ -125,11 +127,13 @@ private void appendChildElements(Element resultElement, Element memberDef) {
for (int i = 0; i < occurances; i++) {
String typeDef = memberDef.attr("ref");
if (typeDef != null) {
Element elementDef = elementDefinition(typeDef);
if (isXsdType(elementDef.type())) {
resultElement.add(targetNamespace().el(elementDef.name(), randomData(elementDef)));
Element elementDef = elementDefinition(qualifiedName(typeDef));
QualifiedName memberType = qualifiedName(elementDef.type());
if (isXsdType(memberType)) {
resultElement.add(targetNamespace().el(elementDef.name(),
randomElementText(elementDef.text(), elementDef)));
} else {
resultElement.add(createRandomElement(elementDef.type()));
resultElement.add(createRandomElement(memberType));
}
continue;
}
Expand All @@ -144,12 +148,12 @@ private void appendChildElements(Element resultElement, Element memberDef) {
} else {
Element el = Xml.el(memberDef.name());
Element simpleMemberType = memberDef.find("simpleType", "restriction").single();
el.text(randomData(simpleMemberType));
el.text(randomElementText(memberDef.name(), simpleMemberType));
resultElement.add(el);
}
} else if (isXsdType(memberDef.type())) {
Element el = Xml.el(memberDef.attr("name"));
el.text(randomData(memberDef));
} else if (isXsdType(qualifiedName(memberDef.type()))) {
Element el = Xml.el(memberDef.name());
el.text(randomElementText(memberDef.name(), memberDef));
resultElement.add(el);
} else {
Element element = Xml.el(memberDef.name());
Expand All @@ -159,6 +163,30 @@ private void appendChildElements(Element resultElement, Element memberDef) {
}
}

/**
* Override this method to create custom rules for specific attributes
* @param attributeName The name of the attribute to write
* @param attrDef The element that defines the attribute
* @return Random attribute value that fulfills the definition
*/
protected String randomAttributeText(String attributeName, Element attrDef) {
return randomData(attrDef);
}

/**
* Override this method to create custom rules for specific elements
* @param elementName The name of the element to write
* @param attrDef The element that defines the attribute
* @return Random attribute value that fulfills the definition
*/
protected String randomElementText(String elementName, Element typeDefinition) {
return randomData(typeDefinition);
}

private boolean isXsdType(QualifiedName type) {
return type != null && type.getNamespace().equals(xsNamespace);
}

private int occurences(Element seqMemberDef) {
int occurences = 1;
if (seqMemberDef.hasAttr("maxOccurs") && !seqMemberDef.attr("maxOccurs").equals("1")) {
Expand All @@ -173,7 +201,26 @@ private int occurences(Element seqMemberDef) {
return occurences;
}

private String randomData(Element typeDef) {
private Instant randomDateTime() {
return ZonedDateTime.now().minusDays(100).plusMinutes(new Random().nextInt(200 * 24 * 60)).toInstant();
}

protected String randomData(Element typeDef) {
if ("simpleType".equals(typeDef.tagName())) {
String baseType = typeDef.find("restriction").single().attr("base");

ElementSet enumerations = typeDef.find("restriction", "enumeration");
if (enumerations.isPresent()) {
return pickOne(enumerations.attrs("value"));
}

if (baseType.matches(xsNamespace.name("string").print())) {
return "123-AB";
} else {
throw new RuntimeException("Don't know what to do with " + baseType);
}
}

String type = typeDef.type();
if (type == null)
type = typeDef.attr("base");
Expand All @@ -184,29 +231,22 @@ private String randomData(Element typeDef) {
} else if (type.matches(xsNamespace.name("string").print())) {
return randomString(10, 20);
} else if (type.matches(xsNamespace.name("int").print())) {
return String.valueOf(random(-1000, 10000));
return String.valueOf(random(-10, 10));
} else if (type.matches(xsNamespace.name("positiveInteger").print())) {
return String.valueOf(random(0, 100));
return String.valueOf(random(1, 10));
} else if (type.matches(xsNamespace.name("decimal").print())) {
return String.valueOf(random(-1000, 10000) / 100);
} else if (type.matches(xsNamespace.name("float").print())) {
return String.valueOf(random(-1000, 10000) / 100);
} else if (type.matches(xsNamespace.name("base64Binary").print())) {
return "sdfmsdlgnsd";
// data:image/svg+xml;base64,
return "PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgdmlld0JveD0iMCAwIDQ4IDQ4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTEsLmNscy0ye2ZpbGw6bm9uZTtzdHJva2U6IzIzMWYyMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6MnB4O30uY2xzLTJ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7fS5jbHMtM3tmaWxsOiMyMzFmMjA7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZS8+PGNpcmNsZSBjbGFzcz0iY2xzLTEiIGN4PSIyNCIgY3k9IjI0IiByPSIyMyIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE0LDMzczguODMsOS4zMywyMCwwIi8+PGVsbGlwc2UgY2xhc3M9ImNscy0zIiBjeD0iMTciIGN5PSIxOSIgcng9IjMiIHJ5PSI0Ii8+PGVsbGlwc2UgY2xhc3M9ImNscy0zIiBjeD0iMzEiIGN5PSIxOSIgcng9IjMiIHJ5PSI0Ii8+PC9zdmc+";
} else if (type.matches(xsNamespace.name("NMTOKEN").print())) {
return typeDef.attr("fixed");
}
throw new IllegalArgumentException("Unknown base type " + type);
}

private boolean isXsdType(String type) {
if (type.contains(":")) {
return type.split(":")[0].equals(xsNamespace.getPrefix());
} else {
return xsNamespace.getPrefix() == null;
}
}

private LocalDate randomDate() {
return LocalDate.now().minusDays(100).plusDays(new Random().nextInt(200));
}
Expand Down Expand Up @@ -243,36 +283,32 @@ private Namespace targetNamespace() {
}

private Element attributeDefinition(String typeNameFull) {
String[] nameParts = typeNameFull.split(":");
String typeName = nameParts.length > 1 ? nameParts[1] : typeNameFull;
String typeName = qualifiedName(typeNameFull).getName();
return schemaDoc.find("attribute[name=" + typeName + "]").single();
}

private Element complexType(String typeNameFull) {
String[] nameParts = typeNameFull.split(":");
String typeName = nameParts.length > 1 ? nameParts[1] : typeNameFull;
Element typeDefinition = schemaDoc.find("complexType[name=" + typeName + "]").singleOrDefault();
Element typeDefinition = schemaDoc.find("complexType[name=" + qualifiedName(typeNameFull).getName() + "]").singleOrDefault();
if (typeDefinition != null) {
return typeDefinition;
}
for (Document schemaDoc : includedSchemas) {
typeDefinition = schemaDoc.find("complexType[name=" + typeName + "]").singleOrDefault();
typeDefinition = schemaDoc.find("complexType[name=" + qualifiedName(typeNameFull).getName() + "]").singleOrDefault();
if (typeDefinition != null) {
return typeDefinition;
}
}
throw new IllegalArgumentException("Can't find type definition of " + typeName);
throw new IllegalArgumentException("Can't find type definition of " + qualifiedName(typeNameFull).getName());
}

private Element elementDefinition(String elementNameFull) {
String[] nameParts = elementNameFull.split(":");
String elementName = nameParts.length > 1 ? nameParts[1] : elementNameFull;
Element typeDefinition = schemaDoc.find("element[name=" + elementName + "]").singleOrDefault();
private Element elementDefinition(QualifiedName elementName) {
// TODO: Lookup schema based on elementName namespace
Element typeDefinition = schemaDoc.find("element[name=" + elementName.getName() + "]").singleOrDefault();
if (typeDefinition != null) {
return typeDefinition;
}
for (Document schemaDoc : includedSchemas) {
typeDefinition = schemaDoc.find("element[name=" + elementName + "]").singleOrDefault();
typeDefinition = schemaDoc.find("element[name=" + elementName.getName() + "]").singleOrDefault();
if (typeDefinition != null) {
return typeDefinition;
}
Expand Down

0 comments on commit 74d7107

Please sign in to comment.