Чтобы определить, когда начинать новый раздел, я сделал это:
<xsl:if test="@TheFirstCol>preceding-sibling::*[1]/@TheFirstCol"
Может ли это быть причиной или повторения?
Определенно. Выбранный вами алгоритм O (N 2 ) и будет очень медленным при достаточном количестве братьев и сестер, независимо от языка реализации.
Вот эффективный алгоритм с использованием ключей:
Solution1:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kC1Value" match="@c1" use="."/>
<xsl:template match="/">
<xsl:for-each select="*/x[generate-id(@c1) = generate-id(key('kC1Value',@c1)[1])]">
<xsl:value-of select="concat('
',@c1)"/>
<xsl:for-each select="key('kC1Value',@c1)">
<xsl:value-of select="'
'"/>
<xsl:for-each select="../@*[not(name()='c1')]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
К сожалению, XslTransform (.Net 1.1) имеет общеизвестно неэффективную реализацию функции generate-id()
.
Следующее может быть быстрее с XslTransform:
Solution2:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kC1Value" match="@c1" use="."/>
<xsl:template match="/">
<xsl:for-each select="*/x[count(@c1 | key('kC1Value',@c1)[1]) = 1]">
<xsl:value-of select="concat('
',@c1)"/>
<xsl:for-each select="key('kC1Value',@c1)">
<xsl:value-of select="'
'"/>
<xsl:for-each select="../@*[not(name()='c1')]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
При применении к следующему небольшому документу XML:
<t>
<x c1="1" c2="0" c3="0" c4="0" c5="0"/>
<x c1="1" c2="0" c3="1" c4="0" c5="0"/>
<x c1="1" c2="2" c3="0" c4="0" c5="0"/>
<x c1="1" c2="1" c3="1" c4="0" c5="0"/>
<x c1="2" c2="0" c3="0" c4="0" c5="0"/>
<x c1="2" c2="0" c3="1" c4="0" c5="0"/>
<x c1="2" c2="2" c3="0" c4="0" c5="0"/>
<x c1="2" c2="1" c3="1" c4="0" c5="0"/>
<x c1="3" c2="0" c3="0" c4="0" c5="0"/>
<x c1="3" c2="0" c3="1" c4="0" c5="0"/>
<x c1="3" c2="2" c3="0" c4="0" c5="0"/>
<x c1="3" c2="1" c3="1" c4="0" c5="0"/>
<x c1="3" c2="0" c3="0" c4="0" c5="0"/>
<x c1="3" c2="0" c3="1" c4="0" c5="0"/>
<x c1="3" c2="2" c3="0" c4="0" c5="0"/>
<x c1="3" c2="1" c3="1" c4="0" c5="0"/>
<x c1="4" c2="0" c3="0" c4="0" c5="0"/>
<x c1="4" c2="0" c3="1" c4="0" c5="0"/>
<x c1="4" c2="2" c3="0" c4="0" c5="0"/>
<x c1="4" c2="1" c3="1" c4="0" c5="0"/>
<x c1="5" c2="0" c3="0" c4="0" c5="0"/>
<x c1="5" c2="0" c3="1" c4="0" c5="0"/>
<x c1="5" c2="2" c3="0" c4="0" c5="0"/>
<x c1="5" c2="1" c3="1" c4="0" c5="0"/>
<x c1="5" c2="0" c3="0" c4="0" c5="0"/>
<x c1="5" c2="0" c3="1" c4="0" c5="0"/>
<x c1="6" c2="2" c3="0" c4="0" c5="0"/>
<x c1="6" c2="1" c3="1" c4="0" c5="0"/>
<x c1="6" c2="0" c3="0" c4="0" c5="0"/>
<x c1="6" c2="0" c3="1" c4="0" c5="0"/>
<x c1="6" c2="2" c3="0" c4="0" c5="0"/>
<x c1="6" c2="1" c3="1" c4="0" c5="0"/>
<x c1="7" c2="0" c3="0" c4="0" c5="0"/>
<x c1="7" c2="0" c3="1" c4="0" c5="0"/>
<x c1="7" c2="2" c3="0" c4="0" c5="0"/>
<x c1="7" c2="1" c3="1" c4="0" c5="0"/>
<x c1="8" c2="0" c3="0" c4="0" c5="0"/>
<x c1="8" c2="0" c3="1" c4="0" c5="0"/>
<x c1="8" c2="2" c3="0" c4="0" c5="0"/>
<x c1="8" c2="1" c3="1" c4="0" c5="0"/>
</t>
оба решения дали желаемый результат:
1
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
2
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
3
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
4
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
5
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
6
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
7
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
8
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
Из приведенного выше небольшого XML-файла я сгенерировал XML-файл размером 10 МБ, скопировав каждый элемент 6250 раз (используя другое преобразование XSLT :)).
В xml-файле размером 10 МБ и в XslCompiledTransform (.Net 2.0 +) оба решения имели следующие времена преобразования:
Решение 1: 3,3 с.
Решение 2: 2,8 с.
С помощью XslTransform (.Net 1.1) Solution2 работал в течение 1622 секунд; это около 27 минут.