diff --git a/docs/asciidoc/modules/ROOT/nav.adoc b/docs/asciidoc/modules/ROOT/nav.adoc
index ef3ac084a5..5fe025da14 100644
--- a/docs/asciidoc/modules/ROOT/nav.adoc
+++ b/docs/asciidoc/modules/ROOT/nav.adoc
@@ -26,6 +26,8 @@ include::partial$generated-documentation/nav.adoc[]
** xref::import/load-csv.adoc[]
** xref::import/xls.adoc[]
** xref::import/html.adoc[]
+ ** xref::import/parquet.adoc[]
+ ** xref::import/gexf.adoc[]
* xref:export/index.adoc[]
** xref::export/xls.adoc[]
diff --git a/docs/asciidoc/modules/ROOT/pages/import/gexf.adoc b/docs/asciidoc/modules/ROOT/pages/import/gexf.adoc
new file mode 100644
index 0000000000..ec06ff1c6a
--- /dev/null
+++ b/docs/asciidoc/modules/ROOT/pages/import/gexf.adoc
@@ -0,0 +1,222 @@
+[[gexf]]
+= Load GEXF (Graph Exchange XML Format)
+:description: This section describes procedures that can be used to import data from GEXF files.
+
+
+
+Many existing applications and data integrations use GEXF to describes a graph with nodes and edges.
+For further information, you should visit the https://gexf.net/[official documentation].
+
+It is possible to load or import nodes and relationship from a GEXF file with the procedures
+ `apoc.load.gexf` and `apoc.import.gexf`. You need to:
+
+* provide a path to a GEXF file
+* provide configuration (optional)
+
+The `apoc.import.gexf` read as the `apoc.load.gexf` but also create nodes and relationships in Neo4j.
+
+For reading from files you'll have to enable the config option:
+
+----
+apoc.import.file.enabled=true
+----
+
+By default file paths are global, for paths relative to the `import` directory set:
+
+----
+apoc.import.file.use_neo4j_config=true
+----
+
+== Examples for apoc.load.gexf
+
+.load.gexf
+----
+
+
+
+
+
+
+
+
+
+
+
+
+----
+
+[source, cypher]
+----
+CALL apoc.load.gexf('load.gexf')
+----
+
+.Results
+[opts="header"]
+|===
+| value
+| {_type: gexf, _children: [{_type: graph, defaultedgetype: directed, _children: [{_type: nodes, _children: [{_type: node, _children: [{_type: attvalues, _children: [{_type: attvalue, for: 0, value: http://gephi.org}]}], foo: bar}]}]}], version: 1.2}
+|===
+
+== Examples for apoc.import.gexf
+
+Besides the file you can pass in a config map:
+
+.Config parameters
+[opts=header]
+|===
+| name | type | default | description
+| readLabels | Boolean | false | Creates node labels based on the value in the `labels` property of `node` elements
+| defaultRelationshipType | String | RELATED | The default relationship type to use if none is specified in the GraphML file
+| storeNodeIds | Boolean | false | store the `id` property of `node` elements
+| batchSize | Integer | 20000 | The number of elements to process per transaction
+| compression | `Enum[NONE, BYTES, GZIP, BZIP2, DEFLATE, BLOCK_LZ4, FRAMED_SNAPPY]` | `null` | Allow taking binary data, either not compressed (value: `NONE`) or compressed (other values)
+| source | Map | Empty map | See `source / target config` parameter below
+| target | Map | Empty map | See `source / target config` parameter below
+See the xref::overview/apoc.load/apoc.load.csv.adoc#_binary_file[Binary file example]
+|===
+
+
+With the following file will be created:
+
+* 1 node with label Gephi
+* 2 nodes with label Webatlas
+* 1 node with label RTGI
+* 1 node with label BarabasiLab
+* 6 relationships of kind KNOWS
+* 1 relationship of kind HAS_TICKET
+* 1 relationship of kind BAZ
+
+.data.gexf
+----
+
+
+
+ Gephi.org
+ A Web network
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+----
+
+[source, cypher]
+----
+CALL apoc.import.gexf('data.gexf', {readLabels:true})
+----
+
+.Results
+[opts="header"]
+|===
+| value
+| {
+"relationships" : 8,
+"batches" : 0,
+"file" : "file:/../data.gexf",
+"nodes" : 5,
+"format" : "gexf",
+"source" : "file",
+"time" : 9736,
+"rows" : 0,
+"batchSize" : -1,
+"done" : true,
+"properties" : 21
+}
+|===
+
+We can also store the node IDs by executing:
+[source, cypher]
+----
+CALL apoc.import.gexf('data.gexf', {readLabels:true, storeNodeIds: true})
+----
+
+=== source / target config
+
+Allows the import of relations in case the source and / or target nodes are not present in the file, searching for nodes via a custom label and property.
+To do this, we can insert into the config map `source: {label: '', id: `''`}` and/or `source: {label: '', id: `''`}`
+In this way, we can search start and end nodes via the source and end attribute of `edge` tag.
+
+For example, with a config map `{source: {id: 'myId', label: 'Foo'}, target: {id: 'other', label: 'Bar'}}`
+with a edge row like `KNOWS`
+we search a source node `(:Foo {myId: 'n0'})` and an end node `(:Bar {other: 'n1'})`.
+The id key is optional (the default is `'id'`).
+
+
+
+
diff --git a/docs/asciidoc/modules/ROOT/pages/import/index.adoc b/docs/asciidoc/modules/ROOT/pages/import/index.adoc
index 8b645759e4..732f3dbd39 100644
--- a/docs/asciidoc/modules/ROOT/pages/import/index.adoc
+++ b/docs/asciidoc/modules/ROOT/pages/import/index.adoc
@@ -13,3 +13,4 @@ For more information on these procedures, see:
* xref::import/xls.adoc[]
* xref::import/html.adoc[]
* xref::import/parquet.adoc[]
+* xref::import/gexf.adoc[]
diff --git a/extended/src/main/java/apoc/load/Gexf.java b/extended/src/main/java/apoc/load/Gexf.java
new file mode 100644
index 0000000000..b7e75571e2
--- /dev/null
+++ b/extended/src/main/java/apoc/load/Gexf.java
@@ -0,0 +1,83 @@
+package apoc.load;
+
+import apoc.Extended;
+import apoc.Pools;
+import apoc.export.util.CountingReader;
+import apoc.export.util.ExportConfig;
+import apoc.export.util.ProgressReporter;
+import apoc.load.util.XmlReadUtil.Import;
+import apoc.result.MapResult;
+import apoc.result.ProgressInfo;
+import apoc.util.FileUtils;
+import apoc.util.Util;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.security.URLAccessChecker;
+import org.neo4j.procedure.Context;
+import org.neo4j.procedure.Description;
+import org.neo4j.procedure.Mode;
+import org.neo4j.procedure.Name;
+import org.neo4j.procedure.Procedure;
+import org.neo4j.procedure.TerminationGuard;
+
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static apoc.load.util.XmlReadUtil.Load.xmlXpathToMapResult;
+
+@Extended
+public class Gexf {
+
+ @Context
+ public GraphDatabaseService db;
+
+ @Context
+ public URLAccessChecker urlAccessChecker;
+
+ @Context
+ public TerminationGuard terminationGuard;
+
+ @Context
+ public Pools pools;
+
+ @Procedure("apoc.load.gexf")
+ @Description("apoc.load.gexf(urlOrBinary, path, $config) - load Gexf file from URL or binary source")
+ public Stream gexf(
+ @Name("urlOrBinary") Object urlOrBinary,
+ @Name(value = "config", defaultValue = "{}") Map config
+ ) throws Exception {
+ return xmlXpathToMapResult(urlOrBinary, urlAccessChecker, terminationGuard, config);
+ }
+
+ @Procedure(name = "apoc.import.gexf", mode = Mode.WRITE)
+ @Description("Imports a graph from the provided GraphML file.")
+ public Stream importGexf(
+ @Name("urlOrBinaryFile") Object urlOrBinaryFile, @Name("config") Map config) {
+ ProgressInfo result = Util.inThread(pools, () -> {
+ ExportConfig exportConfig = new ExportConfig(config);
+ String file = null;
+ String source = "binary";
+ if (urlOrBinaryFile instanceof String) {
+ file = (String) urlOrBinaryFile;
+ source = "file";
+ }
+ ProgressReporter reporter = new ProgressReporter(null, null, new ProgressInfo(file, source, "gexf"));
+ Import graphReader = new Import(db)
+ .reporter(reporter)
+ .batchSize(exportConfig.getBatchSize())
+ .relType(exportConfig.defaultRelationshipType())
+ .source(exportConfig.getSource())
+ .target(exportConfig.getTarget())
+ .nodeLabels(exportConfig.readLabels());
+
+ if (exportConfig.storeNodeIds()) graphReader.storeNodeIds();
+
+ try (CountingReader reader =
+ FileUtils.readerFor(urlOrBinaryFile, exportConfig.getCompressionAlgo(), urlAccessChecker)) {
+ graphReader.parseXML(reader, terminationGuard);
+ }
+
+ return reporter.getTotal();
+ });
+ return Stream.of(result);
+ }
+}
diff --git a/extended/src/main/java/apoc/load/util/XmlReadUtil.java b/extended/src/main/java/apoc/load/util/XmlReadUtil.java
new file mode 100644
index 0000000000..9179d7e9e9
--- /dev/null
+++ b/extended/src/main/java/apoc/load/util/XmlReadUtil.java
@@ -0,0 +1,726 @@
+package apoc.load.util;
+
+import apoc.export.util.BatchTransaction;
+import apoc.export.util.CountingInputStream;
+import apoc.export.util.ExportConfig;
+import apoc.export.util.Reporter;
+import apoc.result.MapResult;
+import apoc.util.CompressionAlgo;
+import apoc.util.FileUtils;
+import apoc.util.JsonUtil;
+import apoc.util.Util;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.WordUtils;
+import org.neo4j.graphdb.Entity;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Label;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.Transaction;
+import org.neo4j.graphdb.security.URLAccessChecker;
+import org.neo4j.procedure.TerminationGuard;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import static apoc.load.util.XmlReadUtil.Load.generateXmlDoctypeException;
+import static apoc.util.CompressionConfig.COMPRESSION;
+import static apoc.util.ExtendedUtil.toValidValue;
+
+/**
+ * Taken from Xml
+ * placed in APOC Core
+ */
+public class XmlReadUtil {
+
+ public static class Load {
+ public static Stream xmlXpathToMapResult(
+ Object urlOrBinary, URLAccessChecker urlAccessChecker, TerminationGuard terminationGuard, Map config) throws Exception {
+ if (config == null) config = Collections.emptyMap();
+ boolean failOnError = (boolean) config.getOrDefault("failOnError", true);
+ String path = (String) config.getOrDefault("path", "/");
+ boolean simpleMode = Util.toBoolean(config.getOrDefault("simpleMode", false));
+ try {
+ Map headers = (Map) config.getOrDefault("headers", Collections.emptyMap());
+ CountingInputStream is = FileUtils.inputStreamFor(
+ urlOrBinary,
+ headers,
+ null,
+ (String) config.getOrDefault(COMPRESSION, CompressionAlgo.NONE.name()),
+ urlAccessChecker);
+ return parse(is, simpleMode, path, failOnError, terminationGuard);
+ } catch (Exception e) {
+ if (!failOnError) return Stream.of(new MapResult(Collections.emptyMap()));
+ else throw e;
+ }
+ }
+
+ private static Stream parse(InputStream data, boolean simpleMode, String path, boolean failOnError, TerminationGuard terminationGuard)
+ throws Exception {
+ List result = new ArrayList<>();
+ try {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ documentBuilderFactory.setIgnoringElementContentWhitespace(true);
+ documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ documentBuilder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
+
+ Document doc = documentBuilder.parse(data);
+ XPathFactory xPathFactory = XPathFactory.newInstance();
+
+ XPath xPath = xPathFactory.newXPath();
+
+ path = StringUtils.isEmpty(path) ? "/" : path;
+ XPathExpression xPathExpression = xPath.compile(path);
+ NodeList nodeList = (NodeList) xPathExpression.evaluate(doc, XPathConstants.NODESET);
+
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ final Deque