I've got the following graph:
<?xml version="1.0" encoding="utf-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph edgedefault="undirected">
<node id="a">
<data key="d0">some info</data>
</node>
<node id="b"/>
<node id="c">
<data key="d0">some more info</data>
</node>
<node id="d"/>
<edge source="a" target="b"/>
<edge source="a" target="c"/>
<edge source="b" target="c"/>
<edge source="b" target="d"/>
<edge source="c" target="d"/>
</graph>
</graphml>
And I'm trying to use XSLT to create a subset of the graph containing all nodes neighboring node a
.
Desired output:
<?xml version="1.0" encoding="utf-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph edgedefault="undirected">
<node id="b"/>
<node id="c">
<data key="d0">some more info</data>
</node>
<edge source="b" target="c"/>
</graph>
</graphml>
I'm not a real expert of XSLT, but is it possible to do so in steps? i.e. first removing problematic edges, then removing neighborless nodes?
Here is an XSLT 2.0 (can be run with Saxon 9, Altova, XmlPrime, Exselt) based solution using keys:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0"
xpath-default-namespace="http://graphml.graphdrawing.org/xmlns">
<xsl:output indent="yes"/>
<xsl:param name="start-id" as="xs:string" select="'a'"/>
<xsl:key name="node-id" match="node" use="@id"/>
<xsl:key name="source-edge" match="edge" use="@source"/>
<xsl:key name="target-edge" match="edge" use="@target"/>
<xsl:variable name="start-node" select="key('node-id', $start-id)"/>
<xsl:variable name="neighbours"
select="key('node-id', key('source-edge', $start-node/@id)/@target)
| key('node-id', key('target-edge', $start-node/@id)/@source)"/>
<xsl:variable name="neighbour-edges"
select="//edge[@source = $neighbours/@id and @target = $neighbours/@id]"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="graph">
<xsl:copy>
<xsl:copy-of select="$neighbours | $neighbour-edges"/>
</xsl:copy>
</xsl:template>
</xsl:transform>