简体   繁体   中英

How to get image path for <img src=“?”> tag from XML file

I'd like to use an xml file

<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>

in an html table:

<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>

Whats the best way to do this?

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>

Try it yourself here (copy and paste my code into the appropriate boxes):

There's a bug in the suggested output, as <img/> elements must have alt attributes in every version of HTML in which they are present.

Anyway the following does this but without those attributes that can be done from CSS instead (just to keep size down). Adding them back in if desired is 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>

The above assumes you want the path from the file used directly, adding code to transform it in some way (say taking just the last part of the path using substring-after() ) isn't a difficult extension, assuming said transform isn't complicated itself.

Edit:

Myself and JohnB are going into further territory here, the above suffices to answer the original question.

Added to give a fuller answer to JohnB's question. The following is the equivalent code using for-each instead of apply-templates. In theory both a sequential and a state-machine base implementation of an XSLT processor should deal with this identically, though you may find differences in practice (if you told me they were different with a given processor I'd bet a small amount on it being slightly faster with sequential processing and slightly slower with state-machine processing, but I'd only bet a very small amount).

Note that we can't reuse the default template for pic. On the plus-side, if we have a different default template for pic elsewhere (if this were part of a much more complicated stylesheet), we don't need to be clever to differentiate between them, which is the main time that I personally would lean toward 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>

Use XSL. Example here . Btw why do you have the no attribute there ?

Here is a typical solution that adheres to the spirit of XSLT (no <xsl:for-each> ), as short as possible, and parameterized on the desired number of columns in the table.

<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>

When this transformation is applied on the following XML document (based on the provided XML document, but with more pictures that are really colorful and interesting):

<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>

the wanted result is produced (see it also in a browser :) ) :

<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>

Do note :

  1. The use of the XPath mod operator to determine the items of each row.

  2. The use of modes to process the same type of element ( <pic> ) in two different ways.

  3. The use of AVT (attribute-value-templates) to make the code shorter and more understandable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM