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

October 1st, 2004, 11:43 AM
|
|
Authorized User
|
|
Join Date: Sep 2004
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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?
|
|

October 7th, 2004, 05:35 AM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 326
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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.
|
|

October 7th, 2004, 09:44 AM
|
|
Authorized User
|
|
Join Date: Sep 2004
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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.
|
|

October 7th, 2004, 10:15 AM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 1,212
Thanks: 0
Thanked 1 Time in 1 Post
|
|
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
|
|

October 12th, 2004, 12:17 PM
|
|
Authorized User
|
|
Join Date: Sep 2004
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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">
<qm>
</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.
|
|

October 13th, 2004, 04:43 AM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Posts: 1,212
Thanks: 0
Thanked 1 Time in 1 Post
|
|
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">
<qm>
<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
|
|

October 13th, 2004, 09:50 AM
|
|
Authorized User
|
|
Join Date: Sep 2004
Posts: 36
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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.
|
|
 |