Quais são algumas construções úteis para usar XSLT para produzir XSLT?
Pergunta
Eu tenho uma folha de estilo XSLT existente que leva XML e produz bem formatado XHTML. Eu quero fazer uma versão XSL-FO desta folha de estilo para produzir PDF via Apache FOP. O que eu quero saber é o seguinte:
Há algum conveniente usar padrões XSLT que eu preciso aprender a fazer coisas como:
- copiar alguns nós inalterado
- copiar mais de um nó, mas a adição de atributos extra
Eu sei que posso criar novos nós utilizando
<xsl:element>
, mas existem outras coisas úteis que irá precisar. Note-se que enquanto eu não fiz um monte de copiar de um formato XSLT para outro, eu fiz TONELADAS de XML-> XHTML via XSLT por isso estou familiarizado com a maioria do núcleo da linguagem.
Solução
O padrão que você está procurando "transformar identidade modificado" o. A base desta abordagem é a regra identidade transformar, a primeira regra modelo no estilo abaixo. Cada regra depois que representa uma exceção ao comportamento copiando.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- But strip out <foo> elements (including their content) -->
<xsl:template match="foo"/>
<!-- For <bar> elements, strip out start & end tags, but leave content -->
<xsl:template match="bar">
<xsl:apply-templates/>
</xsl:template>
<!-- For <bat> elements, insert an attribute and append a child -->
<xsl:template match="bat">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="id">123</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
O que é menos gratificante para mim sobre o acima é a duplicação de lógica encontrada na última regra modelo. Isso é um monte de código para apenas adicionando um atributo. E imagine se precisamos de um grupo destes. Aqui está uma outra abordagem que nos permite ser mais precisão cirúrgica no que deseja substituir:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<!-- By default, don't add any attributes -->
<xsl:template mode="add-atts" match="*"/>
<!-- For <bat> elements, insert an "id" attribute -->
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Finalmente, este pode ser realizado muito mais longe, usando um modo diferente para cada tipo de edição que você pode querer fazer:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- For <bat> elements, insert an "id" attribute -->
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
<!-- Append <new-element/> to <bat> -->
<xsl:template mode="append" match="bat">
<new-element/>
</xsl:template>
<!-- Insert an element in <foo> content -->
<xsl:template mode="insert" match="foo">
<inserted/>
</xsl:template>
<!-- Add content before the <bar/> and <bat/> elements -->
<xsl:template mode="before" match="bar | bat">
<before-bat-and-bar/>
</xsl:template>
<!-- Add content only after <bat/> -->
<xsl:template mode="after" match="bat">
<after-bat/>
</xsl:template>
<!-- Here's the boilerplate code -->
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:apply-templates mode="before" select="."/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates mode="insert" select="."/>
<xsl:apply-templates/>
<xsl:apply-templates mode="append" select="."/>
</xsl:copy>
<xsl:apply-templates mode="after" select="."/>
</xsl:template>
<!-- By default, don't add anything -->
<xsl:template mode="add-atts" match="*"/>
<xsl:template mode="insert" match="*"/>
<xsl:template mode="append" match="*"/>
<xsl:template mode="before" match="@* | node()"/>
<xsl:template mode="after" match="@* | node()"/>
</xsl:stylesheet>
Em XSLT 2.0, parte do clichê pode ser ligeiramente simplificada, graças a regras de modelo multi-modo:
<!-- By default, don't add anything -->
<xsl:template mode="add-atts
insert
append
before
after" match="@* | node()"/>
Às vezes eu usar todos esses modos personalizados no mesmo estilo, mas mais frequentemente do que não eu adicioná-los preguiçosamente -., Conforme necessário
Outras dicas
O maior obstáculo para a transformação XSLT é que o prefixo de namespace de saída é a mesma que a das instruções XSL reais em sua transformação. Se você usar “xsl:” tanto em suas instruções XSL e sua saída, o seu motor de XSLT não vai saber a diferença entre as instruções XSL deve executar e aqueles que deve saída, para que o seu XSLT não vai analisar. Isto é, a menos que você usar um alias de namespace:
<xsl:namespace-alias stylesheet-prefix="x" result-prefix="xsl"/>
Esta instrução, que é colocado dentro de <xsl:stylesheet />
, permite que você escreva sua marcação resultado em sua transformação usando um prefixo substituto namespace. Mais tarde, quando o documento de saída é criado, o prefixo que você realmente quer será inserido no lugar do alias. Assim, por exemplo, aqui está um modelo que produz um modelo no documento de saída:
<xsl:template match="xsl:template[@match='title']>
<x:template match="title>
<x:apply-templates />
</x:template>
</xsl:template>
Aqui está um artigo bom: http: //www.xml .com / pub / a / 2001/04/04 / trxml /
No passado, eu desenvolveram folhas de estilo XSL-FO e, em seguida, usou o rende-X FO2HTML estilo para converter o XSL-FO em HTML. Ele converte elementos <block>
em <div>
, <inline>
em <span>
, etc.
Eu não usei-los antes, mas você pode considerar tentando HTML2FO estilo . Ou, pelo menos, olhando-os para pedir algumas idéias.
Desde HTML está faltando algumas das construções de paginação que FO fornece pode não dar-lhe tudo o que você precisa para sua saída XSL-FO, mas provavelmente poderia lidar com a maior parte da lógica de conversão de HTML para elemento XSL-FO / atributos no corpo do documento.