Ho un file XML che codifica uno directed acyclic graph (DAG) che rappresenta uno partial order. Questi grafici sono utili per cose come specificare le dipendenze e trovare critical paths. Per i curiosi, la mia attuale applicazione è di specificare le dipendenze dei componenti per un build system, quindi i vertici sono componenti e spigoli che specificano le dipendenze in fase di compilazione. Ecco un semplice esempio:Trovare il grafico aciclico diretto (DAG) Elementi minimi (vertici) con XSLT/XPath?
<?xml version="1.0"?>
<dag>
<vertex name="A">
<directed-edge-to vertex="C"/>
</vertex>
<vertex name="B">
<directed-edge-to vertex="C"/>
<directed-edge-to vertex="D"/>
</vertex>
<vertex name="C">
<directed-edge-to vertex="E"/>
</vertex>
<vertex name="D">
<directed-edge-to vertex="E"/>
</vertex>
<vertex name="E">
<directed-edge-to vertex="G"/>
</vertex>
<vertex name="F">
<directed-edge-to vertex="G"/>
</vertex>
<vertex name="G"/>
</dag>
questo DAG può essere disegnato in questo modo:
mi piacerebbe applicare un XSLTstylesheet che produce un altro documento XML che contiene solo i vertici corrisponde a minimal elements dell'ordine parziale. Cioè quei vertici che non hanno bordi in entrata. L'insieme di vertici minimi per il grafico di esempio è {A, B, F}
. Per la mia applicazione di dipendenza build, trovare questo set è prezioso perché so che se costruisco i membri di questo set, allora tutto il mio progetto sarà costruito.
Ecco la mia attuale soluzione per fogli di stile (sto eseguendo questa operazione con Xalan su Java utilizzando l'attività xslt
di Apache Ant). Un'osservazione chiave è che un vertice minima non farà riferimento a qualsiasi elemento directed-edge-to
:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xslt"
exclude-result-prefixes="xalan">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
<xsl:template match="dag">
<minimal-vertices>
<xsl:for-each select="//vertex">
<xsl:if test="not(//vertex/directed-edge-to[@vertex=current()/@name])">
<minimal-vertex name="{@name}"/>
</xsl:if>
</xsl:for-each>
</minimal-vertices>
</xsl:template>
</xsl:stylesheet>
Applicando questo foglio di stile produce il seguente output (che ritengo sia corretto):
<?xml version="1.0" encoding="UTF-8"?>
<minimal-vertices>
<minimal-vertex name="A"/>
<minimal-vertex name="B"/>
<minimal-vertex name="F"/>
</minimal-vertices>
La cosa è, Non sono completamente soddisfatto di questa soluzione. Mi chiedo se sia possibile combinare loe lo test
dello if
con la sintassi XPath.
voglio scrivere qualcosa di simile:
<xsl:for-each select="//vertex[not(//vertex/directed-edge-to[@vertex=current()/@name])]">
Ma questo non fare quello che voglio perché la funzione current()
non fa riferimento ai nodi selezionati dal esterna //vertex
espressione.
thusfar, la mia soluzione usa XPath 1.0 e XSLT 1.0 sintassi, anche se io sono aperto a sintassi XPath 2.0 e XSLT 2.0 pure.
Ecco lo script Ant, se ti piace:
<?xml version="1.0"?>
<project name="minimal-dag" default="default">
<target name="default">
<xslt in="dag.xml" out="minimal-vertices.xml" style="find-minimal-vertices.xsl"/>
</target>
<target name="dot">
<xslt in="dag.xml" out="dag.dot" style="xml-to-dot.xsl"/>
</target>
</project>
L'obiettivo dot
genera codice GraphvizDotlanguage per il rendering grafico.Ecco xml-to-dot.xsl
:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xslt"
exclude-result-prefixes="xalan">
<xsl:output method="text"/>
<xsl:template match="dag">
digraph {
rankdir="BT";
node [style="filled", fillcolor="cyan", fontname="Helvetica"];
<xsl:apply-templates select="//directed-edge-to"/>
}
</xsl:template>
<xsl:template match="directed-edge-to">
<xsl:value-of select="concat(ancestor::vertex/@name, '->', @vertex, ';')"/>
</xsl:template>
</xsl:stylesheet>
L'abbreviazione "//" deve essere evitata quando possibile poiché è molto costosa, causando la ricerca dell'intero sottoalbero radicato nel nodo di contesto. "//" al livello più alto provoca la ricerca dell'intero documento XML. È molto importante * non * usare "//" ogni volta che la struttura del documento XML è nota al momento della scrittura dell'espressione XPath –