Dies kann mit der folgenden XSLT 1.0-Transformation gelöst werden:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<!-- this key selects elements by their "Superset" name -->
<xsl:key name="kElementBySuperset" match="Element" use="
substring-before(@name, '_')"
/>
<!-- this key selects elements by their "Superset_Set" name -->
<xsl:key name="kElementBySet" match="Element" use="
concat(
substring-before(@name, '_'),
'_',
substring-before(substring-after(@name, '_'), '_')
)
" />
<!--- initalize output (note the template modes) -->
<xsl:template match="Set">
<xsl:apply-templates select="Element" mode="Superset">
<xsl:sort select="@name" />
</xsl:apply-templates>
</xsl:template>
<!-- output <Superset> elements, grouped by name -->
<xsl:template match="Element" mode="Superset">
<xsl:variable name="vSupersetName" select="
substring-before(@name, '_')
" />
<xsl:if test="
generate-id()
=
generate-id(key('kElementBySuperset', $vSupersetName)[1])
">
<Superset name="{$vSupersetName}">
<xsl:apply-templates
select="key('kElementBySuperset', $vSupersetName)"
mode="Set"
>
<xsl:sort select="@name" />
</xsl:apply-templates>
</Superset>
</xsl:if>
</xsl:template>
<!-- output <Set> elements, grouped by name -->
<xsl:template match="Element" mode="Set">
<xsl:variable name="vSetName" select="
concat(
substring-before(@name, '_'),
'_',
substring-before(substring-after(@name, '_'), '_')
)"
/>
<xsl:if test="
generate-id()
=
generate-id(key('kElementBySet', $vSetName)[1])
">
<Set name="{substring-after($vSetName, '_')}">
<xsl:apply-templates
select="key('kElementBySet', $vSetName)"
mode="Element"
>
<xsl:sort select="@name" />
</xsl:apply-templates>
</Set>
</xsl:if>
</xsl:template>
<!-- output <Element> elements -->
<xsl:template match="Element" mode="Element">
<xsl:variable name="vElementName" select="
substring-after(
substring-after(@name, '_'),
'_'
)
" />
<Element name="{$vElementName}" />
</xsl:template>
</xsl:stylesheet>
Ausgabe auf mein System, wenn auf Ihr Eingabedokument angewandt:
<Superset name="Superset1">
<Set name="Set1">
<Element name="Element1" />
<Element name="Element2" />
</Set>
<Set name="Set2">
<Element name="Element1" />
</Set>
</Superset>
<Superset name="Superset2">
<Set name="Set1">
<Element name="Element1" />
</Set>
<Set name="Set2">
<Element name="Element1" />
</Set>
</Superset>
Es ist erwähnenswert, dass diese Lösung Fall empfindlich ist. Ich nehme an, das ist in Ihrem Fall wünschenswert (oder zumindest nicht schädlich). Wenn Fall-Unempfindlichkeit erforderlich ist, dann eine Handvoll dieser Beregnung wäre notwendig geworden (wobei „...“ muss natürlich durch die fehlenden Buchstaben ersetzt werden):
translate($anyvalue, 'ABC…XYZ', 'abc…xyz')
ich, dass vermieden, weil es sehr eintönig ist und macht die Lösung (noch mehr) unklar.
Weiterführende Literatur: Eine meiner Lösungen, die einen ähnlichen zweistufigen tut Gruppierung mit zwei <xsl:key>
s hier:
XSLT 3-level grouping on attributes
Es auf die Interna etwas ausführlicher, und es enthält eine lange Erklärung von <xsl:key>
, die ich hier vermeiden möchte. ;-)
Randnotiz: Obwohl das * viel komplizierter aussieht als die Lösung von @ annakata, ist es in der Tat absolut dasselbe. Es verwendet nur separate Vorlagen anstelle von verschachtelten -Aufrufen.Und viele Zeilenumbrüche, die nicht unbedingt notwendig sind. ;-) –
Tomalak
Es liegt ein kleiner Kompilierfehler vor. Ändern Sie "kElementBySuperset" in "kElementBySup" und dann wird das funktionieren. – Aamir
Ja, nur gesehen und behoben. Dies erhalten Sie, wenn Sie den Code hier bearbeiten * nachdem * Sie die getestete Version aus Ihrem Texteditor eingefügt haben ... – Tomalak