Die derzeit akzeptierte Antwort hat O (N^2) Zeitkomplexität, weil es preceding-sibling::*
für jedes Element verwendet .
Hier ist eine Lösung, die effizient mehr sein kann - keine preceding-sibling::*
Achse verwendet:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:variable name="vTop" select="."/>
<xsl:variable name="vNames" select="distinct-values(*/name())"/>
<xsl:variable name="vCountNames" select="count($vNames)"/>
<xsl:for-each select="1 to $vCountNames">
<xsl:variable name="vCol" select="position()"/>
<xsl:for-each select="$vNames">
<xsl:apply-templates select="$vTop/*[name() eq current()][$vCol]"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Wenn diese Transformation auf die folgende XML-Dokument (Das bereitgestellte Fragment von einem oberen (Dokument umgeben angewendet wird Element)):
<t>
<a>t1</a> <a>t2</a>
<b>t3</b> <b>t4</b> <b>t5</b>
<c>t6</c>
</t>
Das gewünschte Ergebnis erzeugt wird (die Werte jedes e lement, wenn sie von Spalten durchlaufen):
t1t3t6t2t4t5
O(N * M)
Diese Lösung ist, wo N die Anzahl der Elemente ist und M die Anzahl ihrer unterschiedlichen Namen.
Also, wenn N = k times M
dann wird diese Lösung asymptotisch k
mal schneller als eine O(N^2)
Lösung sein.
II. Ein einzelner, reine XPath 2.0-Ausdruck, die Elemente in der Spalte weises Besuch:
for $vTop in /*,
$vCol in 1 to count(distinct-values($vTop/*/name())),
$vName in distinct-values($vTop/*/name())
return
$vTop/*[name() eq $vName][$vCol]
XSLT-basierte Verifikation:
<xsl:template match="/*">
<xsl:sequence select=
"for $vTop in /*,
$vCol in 1 to count(distinct-values($vTop/*/name())),
$vName in distinct-values($vTop/*/name())
return
$vTop/*[name() eq $vName][$vCol]
"/>
</xsl:template>
</xsl:stylesheet>
Wenn auf dem gleichen XML-Dokument angewandt , Diese Umwandlung wertet den XPath-Ausdruck aus und gibt das Ergebnis dieser Auswertung aus:
t1t3t6t2t4t5
III. XSLT 1.0 Lösung:
Diese Transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kByName" match="/*/*" use="name()"/>
<xsl:variable name="vDistinctNamed" select=
"/*/*[generate-id() = generate-id(key('kByName', name())[1])]"/>
<xsl:variable name="vNumCols">
<xsl:for-each select="/*/*[generate-id() = generate-id(key('kByName', name())[1])]">
<xsl:sort select=
"count(key('kByName', name()))" data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:value-of select="count(key('kByName', name()))"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/*">
<xsl:for-each select="*[not(position() > $vNumCols)]">
<xsl:variable name="vCol" select="position()"/>
<xsl:for-each select="$vDistinctNamed">
<xsl:variable name="vthisElement" select="/*/*[name() = name(current())][$vCol]"/>
<xsl:if test="$vthisElement">
<xsl:value-of select="concat(/*/*[name() = name(current())][$vCol],', ')"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
, wenn auf dem gleichen XML-Dokument angewendet wird, erzeugt die gleiche korrekte Ergebnis:
t1, t3, t6, t2, t4, t5,
Dies ist unklar. Es gibt keinen semantischen Unterschied zwischen dem ersten und dem zweiten Block. Was meinst du mit "Gruppe"? Sie müssen den _output_ anzeigen, den Sie von der Eingabe erzeugen möchten. Das Einfügen von Zeilenumbrüchen nach jeder Zeichenfolge mit Tags mit demselben Namen ist keine sinnvolle Umwandlung. –
Ich habe die Frage mit hoffentlich einer klareren Beschreibung aktualisiert. – dave