Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
| Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old October 1st, 2004, 11:43 AM
Authorized User
 
Join Date: Sep 2004
Location: , , .
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
Default Ordering results

I'm working on transforming different testing formats into a proprietary tagged language for our online services. I'm currently working on matching questions; i.e.:

Match the author to their work:
___ Edgar Allan Poe A. Moby Dick
___ Shirley Jackson B. The Raven
___ Herman Melville C. The Lottery
                         D. The Scarlet Letter

The XML for this looks like so:

<ItemSet ItemType="Matching">
<Item>
    <AnswerSet>
        <AnswerValue id="moby">Moby Dick</AnswerValue>
        <AnswerValue id="raven">The Raven</AnswerValue>
        <AnswerValue id="lottery">The Lottery</AnswerValue>
        <AnswerValue id="letter">The Scarlet Letter</AnswerValue>
    </AnswerSet>

    <ItemComponents>
        <Question>Edgar Allan Poe<AnswerRef AnswerRef="raven"/></Question>
        <Question>Shirley Jackson<AnswerRef AnswerRef="lottery"/></Question>
        <Question>Herman Melville<AnswerRef AnswerRef="moby"/></Question>
    </ItemComponents>
</Item>
</ItemSet>

The output needs to look like this:

<qm>
Edgar Allan Poe
The Raven
Shirley Jackson
The Lottery
Herman Melville
Moby Dick
NULL
The Scarlet Letter

Because there can be "distractors" (answers that don't correspond to a question, just to confuse the student), I need to generate a NULL for each AnswerValue that doesn't have a question. This would be simple if the XML were marked up like this:

<Question>Edgar Allan Poe<AnswerRef AnswerRef="raven"/></Question>
        <Question>Shirley Jackson<AnswerRef AnswerRef="lottery"/></Question>
        <Question>Herman Melville<AnswerRef AnswerRef="moby"/></Question>
        <Question><AnswerRef AnswerRef="letter"/></Question>

But it's not. So, it seems to me the easiest way to go about this is to start in the AnswerSet/AnswerValue template. From there, for each AnswerValue, look down to the ItemComponents and find the Question whose AnswerRef matches the AnswerValue id. Don't think that should be difficult.

HOWEVER, this will produce the results in the order of the AnswerValues, not in the order of the Questions. Any ideas how I can go about this so that I get the results I need, in the order I need them?

  #2 (permalink)  
Old October 7th, 2004, 05:35 AM
Friend of Wrox
 
Join Date: Oct 2003
Location: Chennai, TamilNadu, India.
Posts: 326
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via ICQ to Santhi Send a message via MSN to Santhi
Default

You start from <ItemComponents> itself,display the questions and then look up for the answers in <AnswerSet>.If the question is null,Display it as NULL ,then check for the answer ids which is not existing in the <ItemComponents> set and display that AnswerValue.
You can add Answerref as an attribute of Question like
<ItemComponents>
     <Question AnswerRef="raven">Edgar Allan Poe</Question>
      ....
</ItemComponents>
Why you have added one more tag for that in Question.


  #3 (permalink)  
Old October 7th, 2004, 09:44 AM
Authorized User
 
Join Date: Sep 2004
Location: , , .
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I'm sorry, either you're misunderstanding or I am. You say, "if the question is Null, display as null." The whole point is, I don't know if the question is null. The problem is, there are more answers than questions. The only way for me to determine which answers don't have corresponding questions is for me to loop through the AnswerSet and search for matching questions. If I had a question tag for questions that were null, it would be simple and there wouldn't be a problem.

If you look at my original code again, this is what I have:

<ItemSet ItemType="Matching">
<Item>
    <AnswerSet>
        <AnswerValue id="moby">Moby Dick</AnswerValue>
        <AnswerValue id="raven">The Raven</AnswerValue>
        <AnswerValue id="lottery">The Lottery</AnswerValue>
        <AnswerValue id="letter">The Scarlet Letter</AnswerValue>
    </AnswerSet>

    <ItemComponents>
        <Question>Edgar Allan Poe<AnswerRef AnswerRef="raven"/></Question>
        <Question>Shirley Jackson<AnswerRef AnswerRef="lottery"/></Question>
        <Question>Herman Melville<AnswerRef AnswerRef="moby"/></Question>
    </ItemComponents>
</Item>
</ItemSet>

So, using your logic, how would I determine that there should be a NULL value added as the "question" for The Scarlet Letter in order to produce this output:

<qm>
Edgar Allan Poe
The Raven
Shirley Jackson
The Lottery
Herman Melville
Moby Dick
NULL
The Scarlet Letter

As for your questioning why I don't just add a question tag for null questions, it's not my choice. I'm the stylesheet developer, and have no say in how the input is marked up. The DTD was signed off on months before I was brought in.

  #4 (permalink)  
Old October 7th, 2004, 10:15 AM
Friend of Wrox
 
Join Date: Jun 2003
Location: , , United Kingdom.
Posts: 1,212
Thanks: 0
Thanked 1 Time in 1 Post
Default

Can't you do something like this:
- start with apply-templates for Question and write out all the Questions and Answers. Then you would easily be able to sort in Q order
- then apply-templates to AnswerValue and only deal with the NULL case within that template, I'm assuming that you always want the NULL case to be at the end.

To identify the NULL case use something like this (assuming the context node is AnswerValue):
xsl:if test="not(path_to_Question/Question[AnswerRef/@AnswerRef = current()/@id])"
   ...output NULL and text()

Haven't had time to try it out, but it should work...

hth
Phil
  #5 (permalink)  
Old October 12th, 2004, 12:17 PM
Authorized User
 
Join Date: Sep 2004
Location: , , .
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Phil, I hope you're still following this; I've been on another project this last week and only just now had a chance to try out your code.

So, it does work, sort of. The problem is, if I use apply-templates for the AnswerValue item (in the question template) it repeats the null items for each question. Example:

<ItemSet ItemType="Matching">
<Item>
<AnswerSet>
<AnswerValue id="turn">Turn of the Screw</AnswerValue>
<AnswerValue id="goodman">Young Goodman Brown</AnswerValue>
<AnswerValue id="lottery">The Lottery</AnswerValue>
<AnswerValue id="raven">The Raven</AnswerValue>
<AnswerValue id="sea">Seabiscuit</AnswerValue>
</AnswerSet>
<ItemComponents>
<Question>Edgar Allan Poe<AnswerRef AnswerRef="raven"/></Question>
<Question>Shirley Jackson<AnswerRef AnswerRef="lottery"/></Question>
</ItemComponents>
</Item>
</ItemSet>

produces this output:

<qm>
Edgar Allan Poe
This is the answer: raven
applying answervalue template:
NULL
Turn of the Screw
NULL
Young Goodman Brown
NULL
Seabiscuit

Shirley Jackson
This is the answer: lottery
applying answervalue template:
NULL
Turn of the Screw
NULL
Young Goodman Brown
NULL
Seabiscuit

when using this code:

<xsl:template match="Question">
<xsl:if test="position() = 1">
&lt;qm&gt;
</xsl:if>
<xsl:value-of select="text()" />


<xsl:variable name="ansID" select="AnswerRef/@AnswerRef" />
This is the answer: <xsl:value-of select="$ansID" />
<!-- this is my trying to get AnswerValue
<xsl:value-of select="ancestor::Item[1]AnswerSet/AnswerValue[@id='{$ansID}']" /> -->
applying answervalue template: <xsl:apply-templates select="ancestor::ItemSet[1]/Item[1]/AnswerSet/AnswerValue" />
</xsl:template>

<xsl:template match="ItemSet/Item/AnswerSet/AnswerValue">
<xsl:if test="not(ancestor::Item[1]/ItemComponents/Question[AnswerRef/@AnswerRef=current()/@id])">
NULL.
<xsl:value-of select="." />
</xsl:if>
</xsl:template>

The output I want is:

<qm>
Edgar Allan Poe
This is the answer: raven
Shirley Jackson
This is the answer: lottery
applying answervalue template:
NULL
Turn of the Screw
NULL
Young Goodman Brown
NULL
Seabiscuit

I've only started working with XSLT about 2 months ago, and this is really beyond my meager skills, so any guidance is much appreciated.

  #6 (permalink)  
Old October 13th, 2004, 04:43 AM
Friend of Wrox
 
Join Date: Jun 2003
Location: , , United Kingdom.
Posts: 1,212
Thanks: 0
Thanked 1 Time in 1 Post
Default

Hi Esther,

I meant that you should apply the template for the NULLs outside of the template for the Qusetions.

Try something like this:
Code:
    <xsl:template match="/">
        <xsl:apply-templates select="ItemSet/Item"/>
    </xsl:template>
    <xsl:template match="Item">
        &lt;qm&gt;

        <xsl:apply-templates select="ItemComponents/Question"/>

        <xsl:apply-templates select="AnswerSet/AnswerValue[not(@id=../../ItemComponents/Question/AnswerRef/@AnswerRef)]"/>
    </xsl:template>
    <xsl:template match="Question">
        <xsl:value-of select="text()"/>
        This is the answer: <xsl:value-of select="../../AnswerSet/AnswerValue[@id=current()/AnswerRef/@AnswerRef]"/>
    </xsl:template>
    <xsl:template match="AnswerValue">
        NULL.
        <xsl:value-of select="." />
    </xsl:template>
Note that I've made the assumption that if you have multiple Q/A's in your XML then each Q/A pair will be in a containing Item node, like this:
Code:
<ItemSet ItemType="Matching">

    <Item>
        <AnswerSet>
            ...
        </AnswerSet>
        <ItemComponents>
            <Question>...</Question>
            <Question>...</Question>
        </ItemComponents>
    </Item>

    <Item>
        <AnswerSet>
            ...
        </AnswerSet>
        <ItemComponents>
            <Question>...</Question>
            <Question>...</Question>
        </ItemComponents>
    </Item>

</ItemSet>
hth
Phil
  #7 (permalink)  
Old October 13th, 2004, 09:50 AM
Authorized User
 
Join Date: Sep 2004
Location: , , .
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanks again for all your help. Unfortunately your suggested stylesheet won't work for me; the code I provided was an extremely simplified version of what I need to deal with. There are actually 15 different question types, determined by an attribute in the ancestor ItemSet. Based on that, when I get to the Question template I call one of 15 different named templates to deal with the question types, as they don't all behave the same way. AnswerSets are not always in the same place, and not always children of Item. Because this is used for publishing books in any of 6 disciplines, the DTD needs to be extremely flexible, which basically means that almost any element is allowed to go anywhere in the XML, but the XSL needs to behave differently for each configuration. I would love it if I could accomplish all I needed to do in a simple 20-line stylesheet like you've provided; unfortunately I'm currently up to 300+ lines, and I haven't even gotten around to dealing with three of the question types yet.

I'll see if I can modify your answer to work for me; and again - thanks.



Similar Threads
Thread Thread Starter Forum Replies Last Post
stupid question to ordering column in table sal21 BOOK: Access 2003 VBA Programmer's Reference 0 May 9th, 2007 08:00 AM
Ordering rows problem ami4quest6 SQL Language 10 October 12th, 2005 01:13 AM
Ordering a dataview Louisa VB.NET 2002/2003 Basics 1 November 11th, 2004 10:04 AM
alternate ordering polecat XSLT 17 October 2nd, 2003 08:35 AM
Ordering lists POL XSLT 3 June 9th, 2003 11:39 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.