Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@
einer Ableitung eines komplexen Typs durch Einschränkung) oder eine Erweiterung sein. (Dies ist flexibler als eine
Erweiterung eines komplexen Typs, da der Ort, an dem die Basisgruppe in die neue Gruppe eingebunden wird, gewählt
werden kann, während neue Elemente bei einer Ableitung durch Erweiterung stets nach dem Basistyp angeordnet werden.)


* xsd FIXED attributes can be omitted
2 changes: 2 additions & 0 deletions xsonify-serializer/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
requires org.mycore.xsonify.xsd;

exports org.mycore.xsonify.serialize;
exports org.mycore.xsonify.serialize.model;
exports org.mycore.xsonify.serialize.model.old;
}
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ private void handleAttribute(SerializationContext context, String attributeName,
throw new SerializationException(
"Multiple XSD attribute definitions found for '" + attributeName + "' in '" +
element.getName() + "'. Unable to determine which one to choose: " + attributeNodes.stream()
.map(XsdNode::getName)
.map(XsdAttribute::getName)
.map(XmlExpandedName::toString)
.collect(Collectors.joining(",")));
}
Expand All @@ -339,7 +339,7 @@ private void handleAttribute(SerializationContext context, String attributeName,
throw new SerializationException("Invalid '" + attributeName + "' attribute found in " + element.getName());
}
// assign attribute -> determine if prefix is required based on the element namespace
XsdNode attributeNode = attributeNodes.get(0);
XsdAttribute attributeNode = attributeNodes.get(0);
String attributeNamespaceUri = attributeNode.getUri();
XmlNamespace attributeNamespace = elementNamespaceUri.equals(attributeNamespaceUri) ?
XmlNamespace.EMPTY :
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package org.mycore.xsonify.serialize;

import org.mycore.xsonify.serialize.detector.XsdDetectorException;
import org.mycore.xsonify.serialize.detector.XsdJsonPrimitiveDetector;
import org.mycore.xsonify.serialize.detector.XsdPrefixConflictDetector;
import org.mycore.xsonify.serialize.detector.XsdRepeatableElementDetector;
import org.mycore.xsonify.serialize.model.JsonModel;
import org.mycore.xsonify.serialize.model.old.JsonNamespace;
import org.mycore.xsonify.xsd.Xsd;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class JsonModelBuilder {

private Xsd xsd;

private SerializerSettings settings;

private XsdPrefixConflictDetector conflictDetector;

private XsdJsonPrimitiveDetector primitiveDetector;

public XsdRepeatableElementDetector repeatableElementDetector;

// key: xml namespace uri
// value: json namespace name
private Map<String, String> namespaceBinding;

public JsonModelBuilder(Xsd xsd, SerializerSettings settings) {
this.settings = settings;
this.xsd = xsd;
this.namespaceBinding = new LinkedHashMap<>();
try {
this.conflictDetector = new XsdPrefixConflictDetector(xsd);
this.primitiveDetector = new XsdJsonPrimitiveDetector(xsd);
this.repeatableElementDetector = new XsdRepeatableElementDetector(xsd);
} catch (XsdDetectorException detectorException) {
// TODO
throw new RuntimeException(detectorException);
}
}

public JsonModel build() throws SerializationException {
Map<String, JsonNamespace> namespaces = buildNamespaces();
//try {
return buildModel(namespaces);
/*} catch (XsdDetectorException detectorException) {
// TODO
throw new RuntimeException(detectorException);
}*/
}

/**
* Sets a custom binding from xml namespace's to json namespaces.
* <ul>
* <li>key: xml namespace uri</li>
* <li>value: json namespace name</li>
* </ul>
*
* @param namespaceBinding the binding
*/
public void setNamespaceBinding(Map<String, String> namespaceBinding) {
this.namespaceBinding = namespaceBinding;
}

protected Map<String, JsonNamespace> buildNamespaces() {
// build default map from xsd
Map<String, String> namespaceMap = this.xsd.collectNamespaces().entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getValue().stream().findFirst().orElseThrow().uri(),
Map.Entry::getKey
));
// overwrite with user specific binding
namespaceMap.putAll(namespaceBinding);
// build
return namespaceMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> new JsonNamespace(entry.getValue()))
);
}

private JsonModel buildModel(Map<String, JsonNamespace> namespaces) {
JsonModel model = new JsonModel();

return model;
}


/*
private JsonModel buildModel(Map<String, JsonNamespace> namespaces)
throws SerializationException, XsdDetectorException {
JsonModel model = new JsonModel(namespaces);
Collection<XsdNode> namedNodes = xsd.getNamedNodes(XsdElement.class, XsdComplexType.class);
for (XsdNode namedNode : namedNodes) {
JsonInterface jsonInterface = new JsonInterface(namedNode);
model.add(jsonInterface);
}
model.cleanupEmptyNamespaces();
update(model);
return model;
}

private void update(JsonModel model) throws XsdDetectorException {
for (JsonNamespace namespace : model.getNamespaces()) {
update(namespace);
}
}

private void update(JsonNamespace namespace) throws XsdDetectorException {
List<JsonInterface> interfaces = namespace.getInterfaces();
updateDuplicateName(interfaces);
updateName(interfaces);
updateProperties(interfaces);
updatePrimitive(interfaces);
}

private void updateDuplicateName(List<JsonInterface> interfaces) {
Set<JsonInterface> tempSet = new HashSet<>();
for (JsonInterface jsonInterface : interfaces) {
XsdNode node = jsonInterface.node();
for (JsonInterface otherInterface : tempSet) {
XsdNode otherNode = otherInterface.node();
boolean sameName = Objects.equals(node.getLocalName(), otherNode.getLocalName());
if (sameName) {
jsonInterface.hasDuplicateName(true);
otherInterface.hasDuplicateName(true);
break;
}
}
tempSet.add(jsonInterface);
}
}

private void updateName(List<JsonInterface> interfaces) {
for (JsonInterface jsonInterface : interfaces) {
jsonInterface.name(getInterfaceName(jsonInterface));
}
}

private void updateProperties(List<JsonInterface> interfaces) {
for (JsonInterface jsonInterface : interfaces) {
jsonInterface.node();
}
}

private void updatePrimitive(List<JsonInterface> interfaces) throws XsdDetectorException {
for (JsonInterface jsonInterface : interfaces) {
if (jsonInterface.node() instanceof XsdElement) {
JsonPrimitive primitive = this.primitiveDetector.detectElementNode((XsdElement) jsonInterface.node());
jsonInterface.setPrimitive(primitive);
}
}
}

protected String getInterfaceName(JsonInterface jsonInterface) {
XsdNode node = jsonInterface.node();
String localName = node.getLocalName();
String baseName = localName.substring(0, 1).toUpperCase() + localName.substring(1);
if (!jsonInterface.hasDuplicateName()) {
return baseName;
}
return baseName + "_" + node.getType();
}
*/
// use namespace to create interface name mods.Mods

/*XmlElement element = context.xmlElement();
if (SerializerSettings.PrefixHandling.OMIT_IF_NO_CONFLICT.equals(settings.elementPrefixHandling())) {
// check name conflict
if (prefixConflictDetector().detect(element)) {
return element.getQualifiedName().toString();
}
// check namespace conflict
String namespaceUri = element.getNamespace().uri();
if (element.getNamespacesInScope().values().stream()
.map(XmlNamespace::uri)
.filter(uri -> uri.equals(namespaceUri))
.count() > 1) {
return element.getQualifiedName().toString();
}
return element.getLocalName();
}
return element.getQualifiedName().toString();*/

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.mycore.xsonify.serialize;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.mycore.xsonify.serialize.model.JsonElementProperty;
import org.mycore.xsonify.serialize.model.JsonModel;
import org.mycore.xsonify.xml.XmlDocument;
import org.mycore.xsonify.xml.XmlElement;

public class Xml2JsonSerializer2 {

private static final ObjectMapper MAPPER = new ObjectMapper();

private JsonModel model;

public Xml2JsonSerializer2(JsonModel model) throws SerializationException {
this.model = model;
}

public ObjectNode serialize(XmlDocument document) throws SerializationException {
XmlElement root = document.getRoot();
ObjectNode json = MAPPER.createObjectNode();

JsonElementProperty jsonElementProperty = model.get(root);
String name = jsonElementProperty.getName();
if (jsonElementProperty.isArray()) {
ArrayNode arrayNode = MAPPER.createArrayNode();
json.set(name, arrayNode);
} else {
ObjectNode objectNode = MAPPER.createObjectNode();
json.set(name, objectNode);
}
return json;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.mycore.xsonify.serialize.model;

import org.mycore.xsonify.serialize.detector.XsdJsonPrimitiveDetector;
import org.mycore.xsonify.xsd.node.XsdAttribute;
import org.mycore.xsonify.xsd.node.XsdElement;
import org.mycore.xsonify.xsd.node.XsdNode;

import java.util.List;

public class JsonAttributeProperty {

private String name;

private final List<XsdNode> path;

private XsdJsonPrimitiveDetector.JsonPrimitive primitive;

public JsonAttributeProperty(List<XsdNode> path) {
this.path = path;
}

public XsdAttribute xsdAttribute() {
if (path.isEmpty()) {
throw new RuntimeException("invalid path");
}
XsdNode lastNode = path.get(path.size() - 1);
if (!(lastNode instanceof XsdAttribute)) {
throw new RuntimeException("invalid path");
}
return (XsdAttribute) lastNode;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.mycore.xsonify.serialize.model;

import org.mycore.xsonify.xsd.node.XsdNode;

import java.util.List;

public class JsonElementLocalProperty extends JsonElementProperty {

public JsonElementLocalProperty(List<XsdNode> path) {
super(path);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.mycore.xsonify.serialize.model;

import org.mycore.xsonify.xsd.node.XsdElement;
import org.mycore.xsonify.xsd.node.XsdNode;

import java.util.List;

public abstract class JsonElementProperty {

private String name;

private final List<XsdNode> path;

private boolean array;

private boolean optional;

public JsonElementProperty(List<XsdNode> path) {
this.path = path;
}

public String getName() {
return name;
}

public List<XsdNode> getPath() {
return path;
}

public boolean isArray() {
return array;
}

public boolean isOptional() {
return optional;
}

public XsdElement xsdElement() {
if (path.isEmpty()) {
throw new RuntimeException("invalid path");
}
XsdNode lastNode = path.get(path.size() - 1);
if (!(lastNode instanceof XsdElement)) {
throw new RuntimeException("invalid path");
}
return (XsdElement) lastNode;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.mycore.xsonify.serialize.model;

import org.mycore.xsonify.xsd.node.XsdNode;

import java.util.List;

public class JsonElementReferenceProperty extends JsonElementProperty {

private final JsonInterface reference;

public JsonElementReferenceProperty(List<XsdNode> path, JsonInterface reference) {
super(path);
this.reference = reference;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.mycore.xsonify.serialize.model;

import org.mycore.xsonify.xsd.node.XsdNode;

import java.util.List;

public class JsonElementTypeProperty extends JsonElementProperty {

private final JsonType type;

public JsonElementTypeProperty(List<XsdNode> path, JsonType type) {
super(path);
this.type = type;
}

}
Loading