Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > XML > another XSLT problem

Reply
Thread Tools

another XSLT problem

 
 
ned786
Guest
Posts: n/a
 
      08-24-2005
Hello,

I'm trying to solve an XSLT problem, and I'm hoping someone can give a
little guidance. I am transforming XML to HTML.

Here's an example of the XML file I'm dealing with, greatly simplified:

-----------------
<root>

<object name="a">
<item name="a1">Text here</item>
<item name="readonlya2">Text here</item>
<item name="a3">Text here</item>
<item name="readonlya4">Text here</item>
<item name="a5">Text here</item>
</object>

<object name="b">
<item name="b1">Text here</item>
<item name="b2">Text here</item>
<item name="b3">Text here</item>
<item name="b4">Text here</item>
<item name="b5">Text here</item>
</object>

</root>
----------------------

An <object> element contains several <item> elements. I handle each
<object> separately.

If an <object> contains no read-only <item> elements (identified by
name="readonly.."), I want to print "None" in the HTML output.

If there is one or more read-only <item> in an <object>, I will display
those read-only <item> elements in an HTML table.

It seemed simple, but I have tried using a key, and a recursive
template, and anything else I could think of. I can't find out if there
are any read-only <item>s before putting something in the result tree.
If I could set a global variable from within a template, then it would
be easy to check that variable to tell whether or not to create a table
or print "None." But that is apparently not possible.

Have I missed something?

Thanks!
Mark

 
Reply With Quote
 
 
 
 
Dimitre Novatchev
Guest
Posts: n/a
 
      08-24-2005

"ned786" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> Hello,
>
> I'm trying to solve an XSLT problem, and I'm hoping someone can give a
> little guidance. I am transforming XML to HTML.
>
> Here's an example of the XML file I'm dealing with, greatly simplified:
>
> -----------------
> <root>
>
> <object name="a">
> <item name="a1">Text here</item>
> <item name="readonlya2">Text here</item>
> <item name="a3">Text here</item>
> <item name="readonlya4">Text here</item>
> <item name="a5">Text here</item>
> </object>
>
> <object name="b">
> <item name="b1">Text here</item>
> <item name="b2">Text here</item>
> <item name="b3">Text here</item>
> <item name="b4">Text here</item>
> <item name="b5">Text here</item>
> </object>
>
> </root>
> ----------------------
>
> An <object> element contains several <item> elements. I handle each
> <object> separately.
>
> If an <object> contains no read-only <item> elements (identified by
> name="readonly.."), I want to print "None" in the HTML output.
>
> If there is one or more read-only <item> in an <object>, I will display
> those read-only <item> elements in an HTML table.
>
> It seemed simple, but I have tried using a key, and a recursive
> template, and anything else I could think of. I can't find out if there
> are any read-only <item>s before putting something in the result tree.
> If I could set a global variable from within a template, then it would
> be easy to check that variable to tell whether or not to create a table
> or print "None." But that is apparently not possible.


Use:

<xsl:stylesheet version="1.0"
xmlnssl="http://www.w3.org/1999/XSL/Transform">
<xslutput method="html"/>

<xsl:template match="object">
<xsl:choose>
<xsl:when test="not(*[starts-with(@name,'readonly')])">
None
</xsl:when>
<xsltherwise>
<table>
<xsl:for-each select="*[starts-with(@name,'readonly')]">
<tr><td><xsl:value-of select="@name"/></td></tr>
</xsl:for-each>
</table>
</xsltherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>



 
Reply With Quote
 
 
 
 
ned786
Guest
Posts: n/a
 
      08-24-2005
Thank you! I will check this out. It worked on my simplified XML file,
I will see what I get on the real thing.

I didn't know you could put a predicate [...] on an asterisk (*), as in
*[starts-with...etc].

Mark

 
Reply With Quote
 
Peter Flynn
Guest
Posts: n/a
 
      08-24-2005
ned786 wrote:

> Hello,
>
> I'm trying to solve an XSLT problem, and I'm hoping someone can give a
> little guidance. I am transforming XML to HTML.
>
> Here's an example of the XML file I'm dealing with, greatly simplified:
>
> -----------------
> <root>
>
> <object name="a">
> <item name="a1">Text here</item>
> <item name="readonlya2">Text here</item>
> <item name="a3">Text here</item>
> <item name="readonlya4">Text here</item>
> <item name="a5">Text here</item>
> </object>
>
> <object name="b">
> <item name="b1">Text here</item>
> <item name="b2">Text here</item>
> <item name="b3">Text here</item>
> <item name="b4">Text here</item>
> <item name="b5">Text here</item>
> </object>
>
> </root>
> ----------------------
>
> An <object> element contains several <item> elements. I handle each
> <object> separately.
>
> If an <object> contains no read-only <item> elements (identified by
> name="readonly.."), I want to print "None" in the HTML output.
>
> If there is one or more read-only <item> in an <object>, I will display
> those read-only <item> elements in an HTML table.
>
> It seemed simple, but I have tried using a key, and a recursive
> template, and anything else I could think of. I can't find out if there
> are any read-only <item>s before putting something in the result tree.


<xsl:template match="object">
<xsl:variable name="roi"
select="count(item[starts-with(@name,'readonly')])"/>
<xsl:choose>
<xsl:when test="$roi=0">
<xsl:text>None</xsl:text>
</xsl:when>
<xsltherwise>
...do some table stuff...
</xsltherwise>
</xsl:choose>
</xsl:template>

> If I could set a global variable from within a template, then it would
> be easy to check that variable to tell whether or not to create a table
> or print "None." But that is apparently not possible.
>
> Have I missed something?


Set a variable. Test it. Keep it simple
The trick is getting to grips with what XPath can do.

///Peter
 
Reply With Quote
 
Soren Kuula
Guest
Posts: n/a
 
      08-24-2005
ned786 wrote:
> I didn't know you could put a predicate [...] on an asterisk (*), as in
> *[starts-with...etc].


That's not the beginning of the predicate; it's the end of the selection
path (and in this case all of the selection path) before it.

Soren
 
Reply With Quote
 
ned786
Guest
Posts: n/a
 
      08-26-2005
Peter,

Wow, that fixes the problem, and it's elegant to boot! Thanks!

Here's the way I had to modify it for my actual XML files:

<xsl:variable name="ro"
select="count(items/item[starts-with(@iname,'dr') or
starts-with(@iname,'hr') or
starts-with(@iname,'usr') or
starts-with(@iname,'szr') or
starts-with(@iname,'ulr') or
starts-with(@iname,'ipr') or
starts-with(@iname,'br') or
starts-with(@iname,'ucr')])"/>
<xsl:choose>
<xsl:when test="$ro=0" >
<p>No read-only items.</p>
</xsl:when>
<xsltherwise>
<table>... etc.
</table>
</xsltherwise>
</xsl:choose>

As you can see, there are actually 8 different strings that indicate
"read-only" (dr, hr, etc.). Now I am trying to figure out how to "NOT"
that count() function above so I can do the same thing for the
remaining writable items: Print "None" if there are none, and put them
in a table if they exist. The following two have failed:

<xsl:variable name="ro"
select="count(items/item[not(starts-with(@iname,'dr')) or
not(starts-with(@iname,'hr')) or
... ])"/>

<xsl:variable name="ro"
select="count(items/item[@iname != starts-with(@iname,'dr') or
@iname != starts-with(@iname,'hr') or

... ])"/>


I'm trying to find the <item> elements that do not have the read-only
indication. If I can get this to work (find NOT read-only), it will
save work. Do you have any further enlightenment?

Regards,
Mark

 
Reply With Quote
 
Peter Flynn
Guest
Posts: n/a
 
      08-26-2005
ned786 wrote:

> Peter,
>
> Wow, that fixes the problem, and it's elegant to boot! Thanks!
>
> Here's the way I had to modify it for my actual XML files:
>
> <xsl:variable name="ro"
> select="count(items/item[starts-with(@iname,'dr') or
> starts-with(@iname,'hr') or
> starts-with(@iname,'usr') or
> starts-with(@iname,'szr') or
> starts-with(@iname,'ulr') or
> starts-with(@iname,'ipr') or
> starts-with(@iname,'br') or
> starts-with(@iname,'ucr')])"/>
> <xsl:choose>
> <xsl:when test="$ro=0" >
> <p>No read-only items.</p>
> </xsl:when>
> <xsltherwise>
> <table>... etc.
> </table>
> </xsltherwise>
> </xsl:choose>
>
> As you can see, there are actually 8 different strings that indicate
> "read-only" (dr, hr, etc.). Now I am trying to figure out how to "NOT"
> that count() function above so I can do the same thing for the
> remaining writable items: Print "None" if there are none, and put them
> in a table if they exist. The following two have failed:
>
> <xsl:variable name="ro"
> select="count(items/item[not(starts-with(@iname,'dr')) or
> not(starts-with(@iname,'hr')) or
> ... ])"/>


The above should work if you change all "or" to "and".
You're negating the condition, so you must negate the conjunction too.

///Peter

> <xsl:variable name="ro"
> select="count(items/item[@iname != starts-with(@iname,'dr') or
> @iname != starts-with(@iname,'hr') or
>
> ... ])"/>
>
>
> I'm trying to find the <item> elements that do not have the read-only
> indication. If I can get this to work (find NOT read-only), it will
> save work. Do you have any further enlightenment?
>
> Regards,
> Mark


 
Reply With Quote
 
ned786
Guest
Posts: n/a
 
      08-31-2005
Your last suggestion also works, Peter, and you are my hero. Thanks!
The problem is fixed and it saves me a tedious maintenance chore.

If you're interested, I had to add in yet another check to make it all
work, and the final gnarly XPath looks like this:

<xsl:variable name="wri"
select="count(items/item[(not(@doc = 'no') and @iname !=
starts-with(@iname,'dr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'hr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'usr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'szr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'ulr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'ipr')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'br')) and
(not(@doc = 'no') and @iname != starts-with(@iname,'ucr'))])"/>

Weirdly, "not(@doc = no)" worked when "@doc != 'no'" did not. But I'm
happy.

Mark

 
Reply With Quote
 
Peter Flynn
Guest
Posts: n/a
 
      09-03-2005
ned786 wrote:

> Your last suggestion also works, Peter, and you are my hero. Thanks!
> The problem is fixed and it saves me a tedious maintenance chore.


My pleasure...

> If you're interested, I had to add in yet another check to make it all
> work, and the final gnarly XPath looks like this:
>
> <xsl:variable name="wri"
> select="count(items/item[(not(@doc = 'no') and @iname !=
> starts-with(@iname,'dr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'hr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'usr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'szr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'ulr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'ipr')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'br')) and
> (not(@doc = 'no') and @iname != starts-with(@iname,'ucr'))])"/>


I'm not clear what this is trying to achieve. @iname is an attribute:
testing its inequality against a boolean like starts-with will probably
have unexpected effects, depending on whether the attribute is present
or not. If present, and starting with 'hr', then the first test should
always evaluate false.

> Weirdly, "not(@doc = no)" worked when "@doc != 'no'" did not. But I'm
> happy.


I have the feeling I've seen this too...possibly not all processors are
happy with negated boolean conditions involving attributes.

///Peter

 
Reply With Quote
 
ned786
Guest
Posts: n/a
 
      09-06-2005
Peter Flynn wrote:
> > <xsl:variable name="wri"
> > select="count(items/item[(not(@doc = 'no') and @iname !=
> > starts-with(@iname,'dr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'hr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'usr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'szr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'ulr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'ipr')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'br')) and
> > (not(@doc = 'no') and @iname != starts-with(@iname,'ucr'))])"/>

>
> I'm not clear what this is trying to achieve. @iname is an attribute:
> testing its inequality against a boolean like starts-with will probably
> have unexpected effects, depending on whether the attribute is present
> or not. If present, and starting with 'hr', then the first test should
> always evaluate false.


Here's what this achieves. This XPath finds all the writable <item>
elements for me, because I can identify them when the iname attribute
does NOT start with one of the read-only strings (hr, usr, ulr, etc.).

If you are questioning the syntax of saying "@iname !=
starts-with(@iname,...)" instead of just "!= starts-with(@iname,...)",
I did it that way because it seemed I had to or it didn't work. When I
remove the "@iname !=", I get the error "Unexpected token != in
expression" and it stops the transform. (I'm using Saxon at the command
line.)

I also tried putting the expression in parentheses like (!=
starts-with(@iname,...)), and the same error occurred. It only worked
when I put "@iname != starts-with(@iname,...)".

At this point I think I will just take the money and run. I can count
on there always being an iname attribute.

Thanks again,
Mark

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
XSLT question: How to lookup another tag's children in XSLT yinglcs@gmail.com XML 18 10-03-2006 11:22 PM
Multiple XSLT Transforms using a Controller XSLT sneill@mxlogic.com XML 2 10-19-2005 11:00 AM
ANN: New low-cost XML Editor, XSLT Editor, XSLT Debugger, DTD/Schema Editor Stylus Studio Java 0 08-03-2004 03:53 PM
xslt alone or xslt/java for static site? ted XML 1 01-26-2004 10:41 AM
[XSLT]Passing values from Javascript to a XSLT variable Benjamin Hillsley XML 3 09-25-2003 04:50 AM



Advertisments