2010-08-08 16 views
7

Me gustaría utilizar un archivo XMLCómo obtener la ruta de la imagen de la etiqueta <img src="?"> de archivo XML

<pics> 
<pic no="1">c:\pic1.jpg</pic> 
<pic no="2">c:\pic2.jpg</pic> 
<pic no="3">c:\pic3.jpg</pic> 
<pic no="4">c:\pic4.jpg</pic> 
<pic no="5">c:\pic5.jpg</pic> 
.... 
</pics> 

en una tabla HTML:

<table cellspacing="2" cellpadding="2" border="0">    
    <tr> 
    <td><img src="" width="150" height="120" /></td> 
    <td><img src="" width="150" height="120" /></td> 
    <td><img src="" width="150" height="120" /></td> 

    </tr> 
    <tr> 
    <td><img src="from xml" width="150" height="120" /></td> 
    <td><img src="from xml" width="150" height="120" /></td> 
    <td><img src="from xml" width="150" height="120" /></td> 
    </tr> 
    <tr> 
    <td><img src="from xml" width="150" height="120" /></td> 
    <td><img src="from xml" width="150" height="120" /></td> 
    <td><img src="from xml" width="150" height="120" /></td> 
    </tr>      
</table> 

Cuál es la mejor manera de hacer esto?

+0

Buena pregunta (+1). Vea mi respuesta para una solución completa que está en el espíritu de XSLT y para una explicación de todos los momentos significativos en la solución. :) –

Respuesta

3

XML:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<?xml-stylesheet type="text/xsl" href="web_page.xsl"?> 
<pics> 
    <pic> 
    <td> 
    <no src="http://farm1.static.flickr.com/160/387667598_ea86c93d81.jpg" width="150" height="120">1</no> 
    </td> 
    <td> 
    <no src="http://farm1.static.flickr.com/160/387667598_ea86c93d81.jpg" width="150" height="120">2</no> 
    </td> 
    <td> 
    <no src="http://farm1.static.flickr.com/160/387667598_ea86c93d81.jpg" width="150" height="120">3</no> 
    </td> 
    </pic> 
    <pic> 
    <td> 
    <no src="http://motherjones.com/files/legacy/mojoblog/funny-cats-a10.jpg" width="150" height="120">4</no> 
    </td> 
    <td> 
    <no src="http://motherjones.com/files/legacy/mojoblog/funny-cats-a10.jpg" width="150" height="120">5</no> 
    </td> 
    <td> 
    <no src="http://motherjones.com/files/legacy/mojoblog/funny-cats-a10.jpg" width="150" height="120">6</no> 
    </td> 
    </pic> 
</pics> 

XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="/"> 
<html> 
<body> 
    <table> 
    <xsl:for-each select="pics/pic"> 
    <tr> 
     <xsl:for-each select="td"> 
     <td><img> 
      <xsl:attribute name="src"> 
      <xsl:value-of select="no//@src"/> 
      </xsl:attribute> 
      <xsl:attribute name="width"> 
      <xsl:value-of select="no//@width"/> 
      </xsl:attribute> 
      <xsl:attribute name="height"> 
      <xsl:value-of select="no//@height"/> 
      </xsl:attribute> 
     </img></td> 
     </xsl:for-each> 
    </tr> 
    </xsl:for-each> 
    </table> 
</body> 
</html> 
</xsl:template> 
</xsl:stylesheet> 

Inténtelo usted mismo aquí (copia y pega el código en el cuadros apropiados):

+0

Esto no trata con la parte más difícil (organizar las columnas de la tabla), es demasiado detallado ('' tiene el mismo resultado) y es buggy ya que no puede tener un elemento de imagen sin un atributo alt y no puede tener un elemento de imagen como hijo de un elemento de cuerpo. –

+1

@Jon: déjame dirigir tus comentarios. ** 1. ** organizar el html de la tabla es trivial, supuse que podría descifrar esa parte, pero para usted actualicé mi ejemplo para hacer exactamente lo que está intentando lograr (pruébelo usted mismo) ** 2. ** su ejemplo es mucho más complicado que el mío, especialmente para alguien que comienza con XSLT, el mío hace lo que tiene que hacer y es simple ** 3. ** No veo cómo funciona, puedes poner el 'img' en cualquier lugar, mi ejemplo ** funciona! ** No estoy seguro de por qué lo votaste. Que tengas un buen día. – JohnB

+1

Estoy de acuerdo con JohnB: la simple es siempre una mejor solución en mi opinión, especialmente si recién estás comenzando a aprender una nueva tecnología: tratar de dominar el concepto es suficientemente difícil sin tener que pasar por taquigrafía críptica, siempre digo, "guárdalo" simple estúpido " – Doug

1

Usar XSL. Ejemplo here. Por cierto, ¿por qué tienes el atributo no ahí?

+1

Por supuesto, incluso está etiquetado como [xslt] ... – kennytm

2

Hay un error en la salida sugerido, como <img/> elementos deben tener alt atributos en cada versión de HTML en la que están presentes.

De todos modos, lo siguiente hace esto, pero sin los atributos que se pueden hacer desde CSS (para mantener el tamaño). Añadiéndolos de nuevo si se desea es trivial:

<xsl:template match="pics"> 
    <table> 
     <xsl:apply-templates select="pic[position() mod 3 = 1]"/> 
    </table> 
</xsl:template> 
<xsl:template match="pic[position() mod 3 = 1]"> 
    <tr> 
     <td> 
      <xsl:if test="2 &gt; count(following-sibling::pic)"> 
       <xsl:attribute name="colspan"> 
        <xsl:value-of select="3 - count(following-sibling::pic)"/> 
       </xsl:attribute> 
      </xsl:if> 
      <img src="{.}" alt="" /> 
     </td> 
     <xsl:apply-templates select="following-sibling::pic[3 &gt; position()]" /> 
    </tr> 
</xsl:template> 
<xsl:template match="pic"> 
    <td><img src="{.}" alt=""/></td> 
</xsl:template> 

Lo anterior presupone que desea que la ruta del archivo utilizado directamente, añadiendo código para transformarlo de alguna manera (decir tomando sólo la última parte de la ruta utilizando substring-after()) no es una extensión difícil, suponiendo que dicha transformación no se complica por sí misma.

Editar:

Yo y JohnB van a más territorio aquí, los anteriores basta para responder a la pregunta original.

Agregado para dar una respuesta más completa a la pregunta de JohnB. El siguiente es el código equivalente que usa for-each en lugar de apply-templates. En teoría, tanto una implementación secuencial como una base de máquina de estado de un procesador XSLT deberían tratar esto de manera idéntica, aunque puede encontrar diferencias en la práctica (si me dijera que eran diferentes con un procesador determinado, apostaría una pequeña cantidad en él). siendo un poco más rápido con el procesamiento secuencial y un poco más lento con el procesamiento de máquina de estado, pero solo apostaría una cantidad muy pequeña).

Tenga en cuenta que no podemos reutilizar la plantilla predeterminada para pic. En el lado positivo, si tenemos una plantilla predeterminada diferente para la foto en otro lugar (si esto fuera parte de una hoja de estilo mucho más complicada), no necesitamos ser listos para diferenciarlos, que es el momento principal que yo personalmente se inclinaría hacia for-each.

<xsl:template match="pics"> 
    <table> 
    <xsl:for-each select="pic[position() mod 3 = 1]"> 
      <tr> 
       <td> 
        <xsl:if test="2 &gt; count(following-sibling::pic)"> 
         <xsl:attribute name="colspan"> 
          <xsl:value-of select="3 - count(following-sibling::pic)"/> 
        </xsl:attribute> 
        </xsl:if> 
        <img src="{.}" alt="" /> 
       </td> 
       <xsl:for-each select="following-sibling::pic[3 &gt; position()]"> 
        <td><img src="{.}" alt=""/></td> 
       </xsl:for-each> 
      </tr> 
     </xsl:for-each> 
    </table> 
</xsl:template> 
+0

+1 forma muy inteligente de generar las columnas! Nunca he hecho algo tan elegante con XSLT. ¿Pero no necesita un bucle alrededor del ''? – JohnB

+0

No necesitamos un bucle, porque las plantillas de aplicación en la tabla tomarán cada tercera imagen en orden y luego se ejecutará la plantilla correspondiente, que a su vez se ocupa de las siguientes dos. O para verlo de otra manera, apply-templates es un bucle, aunque a veces un bucle en un solo elemento. Hay muy poco (si acaso) con lo que puede hacer, cada uno de los cuales no puede hacer con aplicar-templates, y viceversa. La diferencia suele ser más natural en ese momento, que depende del estilo del codificador hasta cierto punto. Me inclino a aplicar-templates como posiblemente más declarativo, y más propicio para reutilizar –

+0

@JohnB He agregado una implementación para cada una y una explicación de la diferencia para responder más completamente a esa pregunta. –

0

Aquí es una solución típica que se adhiere al espíritu de XSLT (sin <xsl:for-each>), tan corto como sea posible, y con parámetros en el número deseado de columnas en la tabla.

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

    <xsl:param name="pNumCols" select="3"/> 

<xsl:template match="pics"> 
    <table cellspacing="2" cellpadding="2" border="0"> 
    <xsl:apply-templates select="pic[position() mod $pNumCols = 1]"/> 
    </table> 
</xsl:template> 

<xsl:template match="pic"> 
    <tr> 
    <xsl:apply-templates mode="process" select= 
    "(. | following-sibling::pic)[not(position() > $pNumCols)]"/> 
    </tr> 
</xsl:template> 

<xsl:template match="pic" mode="process"> 
    <td><img src="{.}" width="150" height="120" /></td> 
</xsl:template> 
</xsl:stylesheet> 

Cuando se aplica esta transformación en el siguiente documento XML (basado en el documento XML proporcionado, pero con más imágenes que son muy colorido e interesante):

<pics> 
<pic no="1">http://col.stb.s-msn.com/i/D7/6A19748C9AA58B938F42099543D2E.jpg</pic> 
<pic no="2">http://col.stb.s-msn.com/i/1F/35A8478AC24EEF95933B5F0E4E394.jpg</pic> 
<pic no="3">http://col.stb.s-msn.com/i/76/3ADA01320CEC8B31D53FACC0C11E.jpg</pic> 
<pic no="4">http://col.stb.s-msn.com/i/92/51BF117987A3279571F06BEB4AE39D.jpg</pic> 
<pic no="5">http://col.stb.s-msn.com/i/9B/9A6E876BA2F7EAE82392C7E7F6C1C.jpg</pic> 
<pic no="6">http://col.stb.s-msn.com/i/50/8CC964E5503A7F61F8AD22A12024.jpg</pic> 
<pic no="7">http://col.stb.s-msn.com/i/C4/F7EF634B7084DA69AAB5AAD05C8922.jpg</pic> 
<pic no="8">http://col.stb.s-msn.com/i/FB/C8367425D67FA391A5E0F8A3E0276B.jpg</pic> 
</pics> 

el resultado deseado se produce (ver también en un navegador :)):

<table cellspacing="2" cellpadding="2" border="0"> 
    <tr> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/D7/6A19748C9AA58B938F42099543D2E.jpg" width="150" height="120"/> 
     </td> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/1F/35A8478AC24EEF95933B5F0E4E394.jpg" width="150" height="120"/> 
     </td> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/76/3ADA01320CEC8B31D53FACC0C11E.jpg" width="150" height="120"/> 
     </td> 
    </tr> 
    <tr> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/92/51BF117987A3279571F06BEB4AE39D.jpg" width="150" height="120"/> 
     </td> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/9B/9A6E876BA2F7EAE82392C7E7F6C1C.jpg" width="150" height="120"/> 
     </td> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/50/8CC964E5503A7F61F8AD22A12024.jpg" width="150" height="120"/> 
     </td> 
    </tr> 
    <tr> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/C4/F7EF634B7084DA69AAB5AAD05C8922.jpg" width="150" height="120"/> 
     </td> 
     <td> 
     <img src="http://col.stb.s-msn.com/i/FB/C8367425D67FA391A5E0F8A3E0276B.jpg" width="150" height="120"/> 
     </td> 
    </tr> 
</table> 

Ten en cuenta :

  1. El uso del operador XPath mod para determinar los elementos de cada fila.

  2. El uso de modos para procesar el mismo tipo de elemento (<pic>) de dos maneras diferentes.

  3. El uso de AVT (plantillas de valor-atributo) para hacer el código más corto y más comprensible.

+0

Parece muy elegante ... pero soy menos que un principiante: nunca tuve tiempo de entender la magia del xslt. intenté copiar y pegar tu código cambiar las imágenes urls e incluso agregar ... Me perdí ... pero gracias de todos modos :) – Asaf

+0

+1 por la única respuesta que no cambia la entrada o usa una plantilla de ladrillo. @Asaf: por supuesto, esta es una solución elegante, pero no involucra "magia". Además, la preferencia por las instrucciones 'xsl: for-each' sobre' xsl: apply-templates' no es un privilegio para principiantes XSLT, es porque hay algún error de interpretación del paradigma declarativo. –

+0

@Alejandro: Gracias, tu opinión es muy valiosa. @Asaf: corre el riesgo de seguir siendo un principiante durante mucho tiempo si no se esfuerza por aprender. –

Cuestiones relacionadas