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.

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top