У меня есть много файлов, похожих на следующий файл .xml, хотя они намного больше:
<?xml version="1.0" encoding="UTF-8"?>
<a version="3.0">
<b bb="P1">
<!--============== b:P1 c:1 ==============-->
<c cc="1">
<d dd="61">d1
</d>
</c>
<!--============== b:P1 c:2 ==============-->
<c cc="2">
<d dd="17">d2
</d>
</c>
</b>
</a>
Для каждого c есть только один предыдущий комментарий.
Я хочувыведите файл с такой же структурой, что и следующий файл a.csv:
1|1|a|0| |0| |0|
2|1|a|1|b|0| |0|
3|1|a|1|b|1|!|0|
3|1|a|1|b|2|c|0|
4|1|a|1|b|2|c|1|d
3|1|a|1|b|3|!|0|
3|1|a|1|b|4|c|0|
4|1|a|1|b|4|c|1|d
Он представляет собой иерархическое дерево для a.xml:
Поле 1 - это полеиерархический уровень.Например, a имеет уровень 1, b имеет уровень 2 и т. Д.
Поля 2, 4, 6 и 8 равны:
- , если текущийуровень узла меньше уровня текущего поля, чем 0
- , иначе общее количество предшествующих братьев и сестер и комментариев плюс один
Поле 3, 5, 7 и9 равны:
- , если уровень текущего узла меньше уровня текущего поля, тогда ""
- , иначе либо "!"если текущему узлу предшествует комментарий или имя узла
В этом примере уровень 3 содержит комментарии.
Я не могу найти хороший способ сделатьдля каждого, который включает в себя как узлы, так и комментарии.Когда я использую <xsl:for-each select="*">
, я только зацикливаюсь на узлах.
Из-за этого я получил следующий xslt, который проверяет, предшествует ли текущему узлу комментарий:
<?xml version="1.0"?>
<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:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="*">
<xsl:variable name="elm01" select="local-name()" />
<xsl:text>1</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|0| |0| |0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm02" select="local-name()" />
<xsl:text>2</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|0| |0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm03" select="local-name()" />
<xsl:if test="preceding-sibling::comment()[1]">
<xsl:text>3</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|!</xsl:text>
<xsl:text>|0|</xsl:text>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:text>3</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<!-- TODO: I want to count the total of preceding siblings and comments -->
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*|comment())+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm03" />
<xsl:text>|0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm04" select="local-name()" />
<xsl:text>4</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm03" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm04" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Однако, когда я запускаю следующую команду:
xsltproc a.xslt a.xml > a.csv
Я получаю следующий файл a.csv:
1|1|a|0| |0| |0|
2|1|a|1|b|0| |0|
3|1|a|1|b|1|!|0|
3|1|a|1|b|1|c|0|
4|1|a|1|b|1|c|1|d
3|1|a|1|b|2|!|0|
3|1|a|1|b|2|c|0|
4|1|a|1|b|2|c|1|d
Обратите внимание, что поле 6 неверно:
равно 1 как для 1-го комментария, так и для 1-го узла c и его дочерних элементов
равно 2 для 2-го комментария и2-й узел c и его потомки
Есть ли у вас какие-либо решения, чтобы предложить?
РЕШЕНИЕ (Тим)
Теперь я могу получить правильныйвывод с использованием следующего файла xslt:
<?xml version="1.0"?>
<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:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="*">
<xsl:variable name="elm01" select="local-name()" />
<xsl:text>1</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|0| |0| |0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm02" select="local-name()" />
<xsl:text>2</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|0| |0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm03" select="local-name()" />
<xsl:if test="preceding-sibling::comment()[1]">
<xsl:text>3</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*|preceding-sibling::comment())"/>
<xsl:text>|!</xsl:text>
<xsl:text>|0|</xsl:text>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:text>3</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*|preceding-sibling::comment())+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm03" />
<xsl:text>|0|</xsl:text>
<xsl:text> </xsl:text>
<xsl:for-each select="*">
<xsl:variable name="elm04" select="local-name()" />
<xsl:text>4</xsl:text>
<xsl:text>|</xsl:text><xsl:value-of select="count(../../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm01" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm02" />
<xsl:text>|</xsl:text><xsl:value-of select="count(../preceding-sibling::*|../preceding-sibling::comment())+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm03" />
<xsl:text>|</xsl:text><xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text><xsl:copy-of select="$elm04" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
В качестве альтернативы вы также можете использовать xslt в ответе Тима, который избавляет от повторений.