Suponha que eu tenha o seguinte XML:
<?xml version="1.0" encoding="utf8"?>
<test>
<list>
<li>a</li>
<li>a</li>
<li begin="true">b</li> <!-- begin of the "b" list -->
<li>b</li>
<li>b</li>
<li end="true">b</li> <!-- end of the "b" list -->
<li>c</li>
<li>c</li>
</list>
</test>
e eu queria dividir essa lista em três listas com base nos atributos begin
e end
usando XSLT 1.0, de modo que o resultado seja:
<list>
<li>a</li>
<li>a</li>
</list>
<list>
<li>b</li>
<li>b</li>
<li>b</li>
<li>b</li>
</list>
<list>
<li>c</li>
<li>c</li>
</list>
Consegui selecionar a primeira e a terceira lista, mas tive dificuldade em corresponder ao intervalo da lista do meio:
<xsl:template match="list">
<list>
<xsl:apply-templates select="li[@begin = 'true']/preceding-sibling::li" />
</list>
<list>
<xsl:apply-templates select="li[...]" /> <!-- Hmm 🤔 -->
</list>
<list>
<xsl:apply-templates select="li[@end = 'true']/following-sibling::li" />
</list>
</xsl:template>
Tentei várias expressões usando position()
and count()
mas não consegui acertar.
Adendo: os atributos begin
e end
são únicos, ou seja, há exatamente um grupo desse tipo na lista original.
No exemplo dado, com apenas 1 grupo marcado (portanto, apenas 3 grupos no total), você poderia usar:
(Eu dividi isso em duas instruções separadas para facilitar a leitura.)
Adicionado:
Se você estiver usando o processador libxslt , poderá aproveitar algumas funções de extensão que ele suporta e fazer:
desde que você declare:
na
xsl:stylesheet
tag inicial.Este xslt retorna o resultado esperado
No caso geral, isso é bem complicado usando o XSLT 1.0 e é muito melhor migrar para o XSLT 2.0+ se puder, onde você tem instruções como
xsl:for-each-group group-starting-with....
.Muito depende de quão geral é o problema, por exemplo, se você pode ter múltiplos "inícios" e "fim" dentro de uma sequência de irmãos, ou talvez até mesmo começos e fins aninhados. (Lembre-se sempre de que um exemplo não define o seu problema: precisamos conhecer o problema geral, não apenas um exemplo dele.)
Uma técnica útil (não apenas na versão 1.0, mas também em versões posteriores) é a "recursão entre irmãos", na qual você aplica um apply-templates no primeiro filho, e este aplica um apply-templates no próximo filho, e assim por diante. Há um exemplo disso aqui:
XSLT 1.0 seleciona todos os nós entre os nós 'flag'
e você pode encontrar outros pesquisando por "XSLT sibling recursion".
A marcação que você nos mostrou é um exemplo de "marcação sobreposta" e há uma vasta literatura sobre o assunto: se você tem muito XML como esse, vale a pena se familiarizar com a teoria.
Poderia ser feito desta forma: