2011-02-26 17 views
5

Estoy tratando de dividir un árbol de elementos según la ubicación de un elemento descendiente. (En particular, estoy tratando de analizar IDML de Adobe.) Me gustaría ser capaz de convertir un árbol que se parece a:XSLT dividió un árbol en un nodo descendente

<ParagraphStyleRange style="foo"> 
<CharacterStyleRange style="bar"> 
    <Content>foo</Content> 
    <Br /> 
    <Content>bar</Content> 
</CharacterStyleRange> 
<CharacterStyleRange style="bop"> 
    <Content>baz</Content> 
    <Br /> 
    <Hyperlink> 
    <Content>boo</Content> 
    <Br /> 
    <Content>meep</Content> 
    </Hyperlink> 
</ParagraphStyleRange> 

en árboles intermedios:

<ParagraphStyleRange style="foo"> 
<CharacterStyleRange style="bar"> 
    <Content>foo</Content> 
</CharacterStyleRange> 
</ParagraphStyleRange> 

<ParagraphStyleRange style="foo"> 
<CharacterStyleRange style="bar"> 
    <Content>bar</Content> 
</CharacterStyleRange> 
<CharacterStyleRange style="bop"> 
    <Content>baz</Content> 
</CharacterStyleRange> 
</ParagraphStyleRange> 

<ParagraphStyleRange style="foo"> 
<CharacterStyleRange style="bop"> 
    <Hyperlink> 
    <Content>boo</Content> 
    </Hyperlink> 
</CharacterStyleRange> 
</ParagraphStyleRange> 

<ParagraphStyleRange style="foo"> 
<CharacterStyleRange style="bop"> 
    <Hyperlink> 
    <Content>meep</Content> 
    </Hyperlink> 
</CharacterStyleRange> 
</ParagraphStyleRange> 

que puedo luego analizar usando XSL normal. (EDITAR: Originalmente mostré las etiquetas <Br/> en su lugar original, pero en realidad no importa si están allí o no, ya que la información que contenían ahora está representada por los elementos divididos. Creo que es probablemente más fácil resolver este problema sin preocuparse de mantenerlos en.)

he intentado utilizar xsl:for-each-group como se sugiere en la especificación XSLT 2.0 (por ejemplo <xsl:for-each-group select="CharacterStyleRange/*" group-ending-with="Br">), pero no puedo encontrar la manera de aplicar que en cada nivel del árbol (pueden aparecer <Br /> etiquetas en cualquier nivel, por ejemplo, dentro de un elemento <Hyperlink> dentro de un elemento <CharacterStyleRange>, y también me limita a tener plantillas que se aplican a la profundidad elegida.

EDITAR: Mi ejemplo de bacalao e muestra solo un lugar donde el árbol necesita ser dividido, pero puede haber cualquier número de puntos de división (siempre el mismo elemento, sin embargo)

EDIT 2: He añadido algunos ejemplos más detallados, para mostrar algunas de las complicaciones.

+1

Buena pregunta, +1. Vea mi respuesta para una solución completa, breve y fácil. :) –

+0

+1 buena pregunta. :-) – LarsH

+0

Fue difícil de encontrar, pero aquí está el duplicado http://stackoverflow.com/questions/3863274/move-separator-elements-upwards-in-xml-hierarchy –

Respuesta

6

Este XSLT 1.0 (y por supuesto, también XSLT 2.0) transformación:

<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="text()"/> 

     <xsl:template match="/"> 
     <xsl:call-template name="Split"> 
      <xsl:with-param name="pSplitters" 
      select="//Br"/> 
     </xsl:call-template> 
     </xsl:template> 

     <xsl:template name="Split"> 
     <xsl:param name="pSplitters"/> 

     <xsl:if test="$pSplitters"> 
      <xsl:for-each select="$pSplitters[1]"> 

      <xsl:call-template name="buildTree"> 
       <xsl:with-param name="pLeafs" select= 
       "preceding-sibling::node()[not(descendant::Br)]"/> 
      </xsl:call-template> 

      <xsl:if test= 
      "not(following-sibling::node()//Br)"> 
       <xsl:call-template name="buildTree"> 
        <xsl:with-param name="pLeafs" select= 
        "following-sibling::node()"/> 
       </xsl:call-template> 
      </xsl:if> 

      <xsl:call-template name="Split"> 
      <xsl:with-param name="pSplitters" select= 
      "$pSplitters[position() > 1]"/> 
      </xsl:call-template> 
      </xsl:for-each> 
     </xsl:if> 
     </xsl:template> 

<xsl:template name="buildTree"> 
    <xsl:param name="pAncestors" select="ancestor::*"/> 
    <xsl:param name="pLeafs"/> 

    <xsl:choose> 
    <xsl:when test="not($pAncestors)"> 
    <xsl:copy-of select="$pLeafs"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:variable name="vtopAncestor" select="$pAncestors[1]"/> 

     <xsl:element name="{name($vtopAncestor)}" 
      namespace="{namespace-uri($vtopAncestor)}"> 
     <xsl:copy-of select= 
      "$vtopAncestor/namespace::* | $vtopAncestor/@*"/> 
     <xsl:call-template name="buildTree"> 
      <xsl:with-param name="pAncestors" 
       select="$pAncestors[position()>1]"/> 
      <xsl:with-param name="pLeafs" select="$pLeafs"/> 
     </xsl:call-template> 
     </xsl:element> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica en el documento XML proporcionado:

<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bar"> 
     <Content>foo</Content> 
     <Br /> 
     <Content>bar</Content> 
    </CharacterStyleRange> 
    <CharacterStyleRange style="bop"> 
     <Content>baz</Content> 
     <Br /> 
     <Hyperlink> 
      <Content>boo</Content> 
      <Br /> 
      <Content>meep</Content> 
     </Hyperlink> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 

produce la deseada, correcta resultado:

<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bar"> 
     <Content>foo</Content> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 
<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bar"> 
     <Content>bar</Content> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 
<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bop"> 
     <Content>baz</Content> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 
<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bop"> 
     <Hyperlink> 
     <Content>boo</Content> 
     </Hyperlink> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 
<ParagraphStyleRange style="foo"> 
    <CharacterStyleRange style="bop"> 
     <Hyperlink> 
     <Content>meep</Content> 
     </Hyperlink> 
    </CharacterStyleRange> 
</ParagraphStyleRange> 
+0

Hm, parece que esto solo le permite dividirse el árbol en un solo lugar Creo que no estaba claro en mi pregunta; puede haber múltiples elementos '
' que cada uno necesita para dividir el árbol. –

+0

@Quentin Smith: Luego debe editar su pregunta y brindar un ejemplo más representativo. –

+0

@Dimitre Novatchev: Gracias por la sugerencia. Trataba de mantener el ejemplo simple, pero supongo que era demasiado simple para ilustrar realmente el problema. He editado la pregunta para tener un ejemplo más grande. –

Cuestiones relacionadas