Repository: tinkerpop Updated Branches: refs/heads/master c9fcc139f -> 31deab213
TINKERPOP-2006 - Fix for valid GraphML export when graph properties of a vertex and edge have similar name Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/cfc7ecef Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/cfc7ecef Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/cfc7ecef Branch: refs/heads/master Commit: cfc7ecefd370ac438afea03f1e6d718f1eff0fbe Parents: 3852c87 Author: Svante Schubert <[email protected]> Authored: Sun Jul 15 20:26:10 2018 +0200 Committer: Svante Schubert <[email protected]> Committed: Sun Jul 15 20:26:10 2018 +0200 ---------------------------------------------------------------------- .../structure/io/graphml/GraphMLTokens.java | 2 + .../structure/io/graphml/GraphMLWriter.java | 77 +++++++++++++------- 2 files changed, 54 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cfc7ecef/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLTokens.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLTokens.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLTokens.java index 921a10f..588e464 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLTokens.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLTokens.java @@ -55,4 +55,6 @@ final class GraphMLTokens { public static final String LONG = "long"; public static final String BOOLEAN = "boolean"; public static final String INT = "int"; + public static final String VERTEX_SUFFIX = "V"; + public static final String EDGE_SUFFIX = "E"; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cfc7ecef/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java index e2a0952..26c5760 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java @@ -18,6 +18,21 @@ */ package org.apache.tinkerpop.gremlin.structure.io.graphml; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.xml.XMLConstants; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import org.apache.commons.collections.CollectionUtils; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; @@ -30,21 +45,6 @@ import org.apache.tinkerpop.gremlin.structure.io.Io; import org.apache.tinkerpop.gremlin.structure.util.Comparators; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import javax.xml.XMLConstants; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; - /** * GraphMLWriter writes a Graph to a GraphML OutputStream. Note that this format is lossy, in the sense that data * types and features of Gremlin Structure not supported by GraphML are not serialized. This format is meant for @@ -65,6 +65,7 @@ public final class GraphMLWriter implements GraphWriter { private final Optional<String> xmlSchemaLocation; private final String edgeLabelKey; private final String vertexLabelKey; + private Collection<String> intersection; private GraphMLWriter(final boolean normalize, final Map<String, String> vertexKeyTypes, final Map<String, String> edgeKeyTypes, final String xmlSchemaLocation, @@ -75,6 +76,7 @@ public final class GraphMLWriter implements GraphWriter { this.xmlSchemaLocation = Optional.ofNullable(xmlSchemaLocation); this.edgeLabelKey = edgeLabelKey; this.vertexLabelKey = vertexLabelKey; + this.intersection = null; } /** @@ -218,20 +220,33 @@ public final class GraphMLWriter implements GraphWriter { final Map<String, String> identifiedEdgeKeyTypes, final XMLStreamWriter writer) throws XMLStreamException { // <key id="weight" for="edge" attr.name="weight" attr.type="float"/> - final Collection<String> vertexKeySet = getVertexKeysAndNormalizeIfRequired(identifiedVertexKeyTypes); + Collection<String> vertexKeySet = getVertexKeysAndNormalizeIfRequired(identifiedVertexKeyTypes); + Collection<String> edgeKeySet = getEdgeKeysAndNormalizeIfRequired(identifiedEdgeKeyTypes); + // in case vertex and edge may have the same attribute name, the key id in graphml have to be different + intersection = CollectionUtils.intersection(vertexKeySet, edgeKeySet); + // speeding-up later checks + if(intersection.isEmpty()){ + intersection = null; + } for (String key : vertexKeySet) { writer.writeStartElement(GraphMLTokens.KEY); - writer.writeAttribute(GraphMLTokens.ID, key); + if(intersection != null && intersection.contains(key)){ + writer.writeAttribute(GraphMLTokens.ID, key.concat(GraphMLTokens.VERTEX_SUFFIX)); + }else{ + writer.writeAttribute(GraphMLTokens.ID, key); + } writer.writeAttribute(GraphMLTokens.FOR, GraphMLTokens.NODE); writer.writeAttribute(GraphMLTokens.ATTR_NAME, key); writer.writeAttribute(GraphMLTokens.ATTR_TYPE, identifiedVertexKeyTypes.get(key)); writer.writeEndElement(); } - - final Collection<String> edgeKeySet = getEdgeKeysAndNormalizeIfRequired(identifiedEdgeKeyTypes); for (String key : edgeKeySet) { writer.writeStartElement(GraphMLTokens.KEY); - writer.writeAttribute(GraphMLTokens.ID, key); + if(intersection != null && intersection.contains(key)){ + writer.writeAttribute(GraphMLTokens.ID, key.concat(GraphMLTokens.EDGE_SUFFIX)); + }else{ + writer.writeAttribute(GraphMLTokens.ID, key); + } writer.writeAttribute(GraphMLTokens.FOR, GraphMLTokens.EDGE); writer.writeAttribute(GraphMLTokens.ATTR_NAME, key); writer.writeAttribute(GraphMLTokens.ATTR_TYPE, identifiedEdgeKeyTypes.get(key)); @@ -260,7 +275,11 @@ public final class GraphMLWriter implements GraphWriter { for (String key : keys) { writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, key); + if(intersection != null && intersection.contains(key)){ + writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); + }else{ + writer.writeAttribute(GraphMLTokens.KEY, key); + } // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph // implementations support it, but out to empty string just in case. writer.writeCharacters(edge.property(key).orElse("").toString()); @@ -284,7 +303,11 @@ public final class GraphMLWriter implements GraphWriter { for (String key : edge.keys()) { writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, key); + if(intersection != null && intersection.contains(key)){ + writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); + }else{ + writer.writeAttribute(GraphMLTokens.KEY, key); + } // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph // implementations support it, but out to empty string just in case. writer.writeCharacters(edge.property(key).orElse("").toString()); @@ -309,7 +332,11 @@ public final class GraphMLWriter implements GraphWriter { for (String key : keys) { writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, key); + if(intersection != null && intersection.contains(key)){ + writer.writeAttribute(GraphMLTokens.KEY, key.concat(GraphMLTokens.VERTEX_SUFFIX)); + }else{ + writer.writeAttribute(GraphMLTokens.KEY, key); + } // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph // implementations support it, but out to empty string just in case. writer.writeCharacters(vertex.property(key).orElse("").toString()); @@ -356,7 +383,7 @@ public final class GraphMLWriter implements GraphWriter { edgeKeySet = identifiedEdgeKeyTypes.keySet(); return edgeKeySet; - } + } private Collection<String> getVertexKeysAndNormalizeIfRequired(final Map<String, String> identifiedVertexKeyTypes) { final Collection<String> keyset; @@ -368,7 +395,7 @@ public final class GraphMLWriter implements GraphWriter { keyset = identifiedVertexKeyTypes.keySet(); return keyset; - } + } private void writeXmlNsAndSchema(final XMLStreamWriter writer) throws XMLStreamException { writer.writeAttribute(GraphMLTokens.XMLNS, GraphMLTokens.GRAPHML_XMLNS);
