2010-10-18 12 views
8

Tengo algunos elementos XML con <ListItem>, y me gustaría ajustar las ejecuciones consecutivas con elementos <List>. Por lo tanto, XML de origen sería algo como esto:¿Cómo puedo envolver un grupo de elementos adyacentes usando XSLT?

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    <Para>Something else</Para> 
</Section> 

Y me gustaría convertirlo en algo como esto:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 

mediante XSLT. Estoy seguro de que es obvio, pero no puedo resolverlo a esta hora de la tarde. ¡Gracias!


Editar: esto puede ser ignorado por la mayoría de la gente.

Este XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<Root> 
    <Story> 
    <Section id="preface"> 
     <ChapterTitle>Redacted</ChapterTitle> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <BulletListItem>Item1</BulletListItem> 
     <BulletListItem>Item2</BulletListItem> 
     <BulletListItem>Item3</BulletListItem> 
     <BulletListItem>Item4</BulletListItem> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <Body>Redacted<Italic>REDACTED</Italic>Redacted</Body> 
     <BulletListItem>Second list Item1</BulletListItem> 
     <BulletListItem>Second list Item2</BulletListItem> 
     <BulletListItem>Second list Item3</BulletListItem> 
     <BulletListItem>Second list Item4</BulletListItem> 
     <Body>Redacted</Body> 
    </Section> 
    </Story> 
</Root> 

Con esta XSL:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:key name="kFollowing" match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]" 
    use="generate-id(preceding-sibling::BulletListItem 
     [not(preceding-sibling::*[1][self::BulletListItem])])"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="BulletListItem 
     [not(preceding-sibling::*[1][self::BulletListItem])]"> 
    <BulletList> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates mode="copy" select="key('kFollowing', generate-id())"/> 
    </BulletList> 
</xsl:template> 

<xsl:template match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]"/> 

<xsl:template match="BulletListItem" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

Cuando procesa con Ruby REXML y XML/XSLT produce este XML (prettyprint salida):

<Root> 
    <Story> 
    <Section id='preface'> 
     <ChapterTitle> 
     Redacted 
     </ChapterTitle> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <BulletList> 
     <BulletListItem> 
      Item1 
     </BulletListItem> 
     <BulletListItem> 
      Item2 
     </BulletListItem> 
     <BulletListItem> 
      Item3 
     </BulletListItem> 
     <BulletListItem> 
      Item4 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item2 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item3 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item4 
     </BulletListItem> 
     </BulletList> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <Body> 
     Redacted 
     <Italic> 
      REDACTED 
     </Italic> 
     Redacted 
     </Body> 
     <BulletList> 
     <BulletListItem> 
      Second list Item1 
     </BulletListItem> 
     </BulletList> 
     <Body> 
     Redacted 
     </Body> 
    </Section> 
    </Story> 
</Root> 

Usted Veremos que las dos listas se atascan y el bit intermedio se pierde. No estoy seguro si esto es un error en las bibliotecas de Ruby o en su XSLT.

+0

Soy demasiado laico para buscar duplicados ... Si alguien publica los enlaces, eliminaré la respuesta. –

+0

Buena pregunta, +1. Vea mi respuesta para una solución eficiente basada en claves. –

+0

Retiro lo que digo sobre lo obvio: P Realmente necesito aprender XSLT ... – Skilldrick

Respuesta

4

Esta hoja de estilo:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()[1]"/> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="ListItem"> 
     <List> 
      <xsl:call-template name="ListItem"/> 
     </List> 
     <xsl:apply-templates select="following-sibling::node() 
             [not(self::ListItem)][1]"/> 
    </xsl:template> 
    <xsl:template match="ListItem[preceding-sibling::node()[1] 
               /self::ListItem]" 
        name="ListItem"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()[1]"/> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::node()[1] 
               /self::ListItem"/> 
    </xsl:template> 
</xsl:stylesheet> 

Salida:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
     <ListItem>item 1</ListItem> 
     <ListItem>item 2</ListItem> 
     <ListItem>item 3</ListItem> 
     <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 

Datos 3: Usando strip-space para lo que es.

+0

¡Lo siento, no pude elegir las dos! – Skilldrick

+0

@Alejandro - extraño ... Cuando ejecuto esta hoja de estilo en la entrada dada, obtengo algo muy diferente. En particular, su 'select = 'following-sibling :: node() [1] [self :: ListItem]' 'pierde el siguiente ListItem porque el primer nodo hermano siguiente es un nodo de texto en blanco. Sin embargo, no veo razón (http://www.w3.org/TR/xslt#strip) por qué ese nodo no fue eliminado. ¡¿Estoy confundido?! – LarsH

+0

@Alejandro: PS esto sucedió en Saxon 6.5.5 en Oxygen. No hay atributos xml: espacio = "preservar" en ninguna parte. – LarsH

5

Esta 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:key name="kFollowing" match="ListItem[preceding-sibling::*[1][self::ListItem]]" 
    use="generate-id(preceding-sibling::ListItem 
     [not(preceding-sibling::*[1][self::ListItem])][1])"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="ListItem 
     [not(preceding-sibling::*[1][self::ListItem])]"> 
    <List> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates mode="copy" select="key('kFollowing', generate-id())"/> 
    </List> 
</xsl:template> 

<xsl:template match="ListItem[preceding-sibling::*[1][self::ListItem]]"/> 

<xsl:template match="ListItem" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica en el documento XML proporcionado:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    <Para>Something else</Para> 
</Section> 

produce el resultado deseado:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
     <ListItem>item 1</ListItem> 
     <ListItem>item 2</ListItem> 
     <ListItem>item 3</ListItem> 
     <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 
+0

@Dimitre: +1 Buena respuesta. Iba a agregar este tipo de solución cuando vi tu. –

+0

¡Gracias, eso funcionó perfectamente! – Skilldrick

+0

@Dimitre - He descubierto un error con esto. He reproducido el caso en mi pregunta. – Skilldrick

Cuestiones relacionadas