Questa trasformazione:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="removeElementsNamed" select="'x'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:if test="not(name() = $removeElementsNamed)">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
quando applicato su qualsiasi documento XML, dicono che questo:
<t>
<a>
<b/>
<x/>
</a>
<c/>
<x/>
<d/>
</t>
produce il risultato corretto voluto - una copia del documento XML di origine in cui qualsiasi occorrenza di elemento avente il nome che è il valore del parametro $removeElementsNamed
, viene cancellata:
<t>
<a>
<b/>
</a>
<c/>
<d/>
</t>
Do atto: In XSLT 1.0 it is syntactically illegal to have a variable or parameter reference inside a template match pattern. Questo è il motivo per cui le soluzioni di @Jan Thomä e @treeMonkey sollevano entrambi un errore con qualsiasi processore compatibile con XSLT 1.0.
Aggiornamento: Ecco una soluzione più complessa, che permette una lista tubo separato di nomi degli elementi - da cancellare, da passare alla trasformazione:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="removeElementsNamed" select="'|x|c|'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:if test=
"not(contains($removeElementsNamed,
concat('|',name(),'|')
)
)
">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Quando applicato alla stessa documento XML (sopra), la trasformazione produce di nuovo il ricercato, corretta in uscita - il documento XML di origine con tutti gli elementi il cui nome sono specificati nel parametro $removeElementsNamed
- cancellato:
<t>
<a>
<b/>
</a>
<d/>
</t>
Update2: la stessa trasformazione come nel Update1, ma scritto in XSLT 2.0:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="removeElementsNamed" select="'|x|c|'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[name() = tokenize($removeElementsNamed, '\|')]"/>
</xsl:stylesheet>
Aggiornamento: Il PO ha aggiunto l'obbligo di essere anche in grado di eliminare tutti gli attributi che hanno alcune specifiche nome.
Ecco la trasformazione leggermente modificato per accogliere questo nuovo requisito:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="removeElementsNamed" select="'x'"/>
<xsl:param name="removeAttributesNamed" select="'n'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:if test="not(name() = $removeElementsNamed)">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:if test="not(name() = $removeAttributesNamed)">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Quando questa trasformazione è applicato sul documento XML sotto (quello usato prima, ma con pochi attributi aggiunti):
<t>
<a>
<b m="1" n="2"/>
<x/>
</a>
<c/>
<x/>
<d n="3"/>
</t>
The Wanted, risultato corretto è prodotto (tutti gli elementi denominati x
e tutti gli attributi di nome n
vengono cancellate):
<t>
<a>
<b m="1"/>
</a>
<c/>
<d/>
</t>
UPDATE2: come ancora una volta richiesto dal PO, ora implementare la capacità di passare lista tubi separati di nomi per la cancellazione di elementi con questi nomi e rispettivamente un elenco tubo separato di nomi per l'eliminazione di attributi con questi nomi:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="removeElementsNamed" select="'|c|x|'"/>
<xsl:param name="removeAttributesNamed" select="'|n|p|'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:if test=
"not(contains($removeElementsNamed,
concat('|', name(), '|')
)
)
">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:if test=
"not(contains($removeAttributesNamed,
concat('|', name(), '|')
)
)
">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Quando questa trasformazione viene applicata sul seguente documento XML:
012.351.641,061 mila
<t>
<a p="0">
<b m="1" n="2"/>
<x/>
</a>
<c/>
<x/>
<d n="3"/>
</t>
The Wanted, risultato corretto è prodotto (elementi con nomi c
e x
e gli attributi con i nomi n
e p
vengono cancellati):
<t>
<a>
<b m="1"/>
</a>
<d/>
</t>
Sei in grado di utilizzare XSLT 2.0? –
@DevNull - Buona domanda. L'ho appena chiesto [qui] (http://stackoverflow.com/questions/9387396/upgrading-xslt-1-0-to-xslt-2-0). – Witman
Grazie a tutto il buon input sulle risposte, la domanda è stata ampliata per chiarire la funzione desiderata, aggiungendo la funzionalità di rimozione degli attributi come una caratteristica distinta (da non mettere insieme alla rimozione degli elementi, ma disponibile nello stesso codice). – Witman