tags:

views:

459

answers:

3

Hi,

I have a list of figure names and width and height informations in separate xml file,

I need to match the figure name in the source xml file and need to insert the width and height information as a attribute in the source xml file.

here the source xml file..

<graphic name="sample.jpg" align="center"/>

expected output xml file

<graphic name="sample.jpg" width="100" depth="200" align="center"/>

figure measurement xml

<figure>
<name>sample.jpg</name>
<width>100</width>
<height>200</height>
</figure>

I have stored source file name attribute value in '$names'. And I have stored figure measure file name attribute value in '$figname'.

my xsl script

<xsl:for-each select="@name">
<xsl:if test="$figname=$name">
<xsl:attribute name="width"><xsl:value-of select="document('figure.xml')/figure/width"/></xsl:attribute>
<xsl:attribute name="depth"><xsl:value-of select="document('figure.xml')/figure/height"/></xsl:attribute>
</xsl:if>
</xsl:for-each>

It works for only the first time, not for all. i have nearly more than 100 images. for all images i need the width and height values. my scripts works only first value. how do i select the all value ?

plase suggest me..

Best Regards, Antony

-------------------------------------------------------------------------------------------

I am sorry, i have used your scripts, but i am not able to get the exact output which i require.

I have given all the clear details here for your consideration.

INPUT XML:

<figure>
<title>Earliest Discoveries</title>
<graphic name="luc26959_0101.eps" align="center"/>
<caption>These lithographs of teeth of Iguanodon are from Mantell original 1825 article.</caption>
</figure>

INPUT FIGURE XML:

<?xml version="1.0"?>
<figuregroup>
  <figure><name>luc26959_0101.eps</name><width>500</width><height>347</height></figure>
  <figure><name>luc26959_0102.eps</name><width>500</width><height>352</height></figure>
  <figure><name>luc26959_0103.eps</name><width>500</width><height>348</height></figure>
  <figure><name>luc26959_0104.eps</name><width>445</width><height>263</height></figure>
  <figure><name>luc26959_0105.eps</name><width>217</width><height>250</height></figure>
</figuregroup>

TRANSFORMATION XSL CODE:

<xsl:template match="graphic">
<xsl:variable name="names">
<xsl:value-of select="substring-before(@name, '.')"/>
</xsl:variable>
<xsl:for-each select="//graphic">
    <imageobject>
     <imagedata>
     <xsl:attribute name="fileref">graphics/<xsl:value-of select="$names"/>.jpg</xsl:attribute>
     <xsl:attribute name="width"><xsl:value-of select="document('../input/fig.xml')/figuregroup/figure[name=$names]/width"/></xsl:attribute>
     <xsl:attribute name="depth"><xsl:value-of select="document('../input/fig.xml')/figuregroup/figure[name=$names]/height"/></xsl:attribute>
       <xsl:apply-templates/>
       </imagedata>
     </imageobject>
</xsl:for-each>
</xsl:template>

CURRENT OUTPUT XML:

<figure>
<title>Earliest Discoveries</title>
<mediaobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="" depth=""/></imageobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="" depth=""/></imageobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="" depth=""/></imageobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="" depth=""/></imageobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="" depth=""/></imageobject>
    <caption><para>These lithographs of teeth of <emphasis>Iguanodon</emphasis> are from Mantell's original 1825 article.</para><para/></caption>
</mediaobject>
</figure>

REQUIRED OUTPUT:

<figure>
<title>Earliest Discoveries</title>
<mediaobject>
    <imageobject><imagedata fileref="graphics/luc26959_0101.jpg" width="500" depth="347"/></imageobject>
    <caption><para>These lithographs of teeth of <emphasis>Iguanodon</emphasis> are from Mantell's original 1825 article.</para><para/></caption>
</mediaobject>
</figure>

Hope i have given a clear picture about my requirement, i have tried with-out "for-each" also, when i give without 'for-each' i am not getting any output element repeatly, only one time i m getting it, still width and depth attributes empty.

I dont know how to fill that attribute in the correct way, after using your code also.

Please help me..

Thanks & Regards, Antony

+4  A: 

There are a number of things wrong with your approach.

First of all, variables can only be assigned values once, and never again. I suspect that the code you're not showing us is assigning variables under the assumption that they are assigned more than once.

Secondly, <for-each select="@name"> will only select one thing: the name attribute, if it is exists, in the current context. You probably want something more like <for-each select="//graphic"> instead.

Then there's how you access figure.xml using the document function. Your example will only get the first height and width, regardless of the name of the image. You need to filter the results, using something like this:

<xsl:attribute name="width">
  <xsl:value-of select="document('figure.xml')//figure[name=$name]/width"/>
</xsl:attribute>

Assuming you've set $name properly, which I covered in my first point.

You haven't given the entire troublesome XSLT snippet, so I can't give you a full correction. From what you have given me, though, I think you'll need to scrap what you have and re-evaluate your approach. What you're doing isn't complicated, but you're obviously new to XSLT and possibly functional programming as well. Here's an example to get you started:

<xsl:template match="/">
  <xsl:for-each select="//graphic">
    <xsl:variable name="name" select="@name"/>
    <xsl:copy>
      <!-- stuff to copy the attributes/children you want, left to the OP -->
      <xsl:attribute name="width">
        <xsl:value-of 
          select="document('figure.xml')//figure[name=$name]/width"/>
      </xsl:attribute>
      <xsl:attribute name="height">
        <xsl:value-of 
          select="document('figure.xml')//figure[name=$name]/height"/>
      </xsl:attribute>
    </xsl:copy>
  </xsl:for-each>
</xsl:template>


EDIT

One thing I can safely say is that you really need to brush up on your XSLT basics. The problems you are experience are relatively simple, and mostly seem to stem from a belief that XSLT is smarter than it really is. That said, here is a script that I believe will cover what you need:

<xsl:template match="graphic">
  <!-- Get the name of the file in the right dir, with a .jpg extension -->
  <xsl:variable
    name="filename" 
    select="concat('graphics/',substring-before(@name, '.'),'.jpg')"
  />

  <!-- Set a variable to preserve the name of the file we're looking up -->
  <xsl:variable name="lookupname" select="@name"/>

  <!-- Look up this particular figure by name for easy access -->
  <xsl:variable
    name="lookup"
    select="document('../input/fig.xml')/figuregroup/figure[name=$lookupname]"
  />

  <imageobject>
    <imagedata>
    <xsl:attribute name="fileref">
      <xsl:value-of select="$filename"/>
    </xsl:attribute>

    <!-- Set the width and depth according to the lookup variable's children -->
    <xsl:attribute name="width">
      <xsl:value-of select="$lookup/width"/>
    </xsl:attribute>
    <xsl:attribute name="depth">
      <xsl:value-of select="$lookup/height"/>
    </xsl:attribute>

    <!-- Apply any more templates as necessary -->
    <xsl:apply-templates/>
    </imagedata>
  </imageobject>
</xsl:template>
Welbog
Just additional: if the data is in the *primary* input file, I'd look at using `xsl:key` to index them by name.
Marc Gravell
I'd avoid things like keys and recursive templates, Marc, because the OP is obviously new. I don't want to overwhelm him with new concepts, but rather apply ones he's already trying to use.
Welbog
Obviously I'd welcome a more XSLT-spirited solution. Using loops in this situation rubs me the wrong way, but they're easier for people who are just getting into XSLT to understand.
Welbog
@Welbog: This solution would gain if you would store the `document('figure.xml')//figure[name=$name]` in a variable first. Not only would overall readability increase, it would also be more efficient. Still +1 from me, and I agree to your "xsl:key" argument.
Tomalak
+1  A: 

Hi Welbog, Thanks for your update, i have used your xslt code as the same in my .xsl file, but i have got the output like this.

<graphic width="365" height="253"/><graphic width="500" height="352"/>
<graphic width="500" height="348"/><graphic width="445" height="263"/>
<graphic width="217" height="250"/><graphic width="153" height="122"/>
<graphic width="442" height="197"/><graphic width="431" height="452"/>
<graphic width="216" height="291"/><graphic width="216" height="291"/>
<graphic width="605" height="293"/><graphic width="608" height="249"/>

The problem is i am getting all together the figure measurement details in single "graphic" place. in every place i am getting all these to gether, i just need which matches the name in that place.

Could you help me to get the tag in the [name] matches place only..?

Antony
I don't understand what you're asking. You'll have to be more clear.
Welbog
actually all the output is coming together several times wherever the <graphic> element is there....input:<figure><graphic name="ant.jpg"/></figure>output:<figure><graphic width="365" height="253"/><graphic width="500" height="352"/><graphic width="500" height="348"/><graphic width="445" height="263"/><graphic width="217" height="250"/><graphic width="153" height="122"/>... etc.</figure>like this i am getting output.but it should be<figure><graphic width="365" height="253"/></figure>in all the figure element i am getting all the graphic measurement details.hope you understand.
Antony
I can only assume things, but it looks like you've got some XPath messed up somewhere, because the snippet I gave you shouldn't be outputting things like that.
Welbog
@Welborg: He is asking for an `<xsl:copy-of select="@*" />`
Tomalak
@Tomalark: I left that as an exercise to the reader.
Welbog
P.S.: Sorry for the extra "r". :-) Usually I copy names to avoid things like that, but alas, not this time. I would not be surprised if that was not the first time I got your name wrong, though.
Tomalak
A: 

As I understand, you have an XML file with a lot of different elements and want to add the width and height to all the <graphic...> elements, without touching the rest of the XML. Am I correct? Then try this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">    
<xsl:output method="xml" indent="yes"/>

<xsl:template match="graphic">
  <xsl:variable name="name" select="@name"/>
  <xsl:copy><xsl:copy-of select="@*"/><xsl:attribute name="width">
    <xsl:value-of select="document('figure.xml')//figure[name=$name]/width"/>
  </xsl:attribute><xsl:attribute name="height">
    <xsl:value-of select="document('figure.xml')//figure[name=$name]/height"/>
  </xsl:attribute></xsl:copy>
</xsl:template>

<xsl:template match="*">
  <xsl:copy><xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="text()"><xsl:copy/></xsl:template>

</xsl:stylesheet>

I used the attribute lookup code that Welbog suggested, so make sure you upvote him.

It copies all elements and attributes as-is (unless I made a mistake) but treats <graphic...> elements specially by also adding the width and height as looked-up in the figure.xml file. Add more templates if you want to treat other elements specially, or omit them.

Ölbaum
Uh... can you indent that correctly? Horizontal scrolling sucks more than vertical scrolling.
Tomalak
OK, sorry. But I had to stick the tags inside <xsl:copy> because otherwise it takes the line breaks as content and then refuses to add attributes. I forgot if there's a way to prevent it.
Ölbaum
Put the xsl:attribute elements before the xsl:copy-of element. Also, that's not the canonical identity transform you've got going on there; it won't copy comments or processing instructions or CDATA sections. See http://en.wikipedia.org/wiki/Identity_transform.
Robert Rossney
Thanks for the pointer, Robert. My XSLT is a bit rusted, it's always helpful.
Ölbaum