Volker Posted April 11, 2006 Posted April 11, 2006 Hi,i have an xml structure like this: <Word> <Chinese>...</Chinese> <PinYin>...</PinYin> </Word> <Word> <Chinese>...</Chinese> <PinYin>...</PinYin> </Word> and i want a table which is sorted by "PinYin" and contains 20 columns each row containing only the data of "Chinese":0 1 2 3 4 ... 1920 21 22 23 24 ... 29...I tried with the following xsl, which gaves me the plain text result <xsl:for-each select="ChineseWordList"> <xsl:for-each select="Word"> <xsl:sort select="PinYin"/> <xsl:value-of select="Chinese"/> <xsl:copy-of select="' '"/> <xsl:if test="position() mod 20 = 0"><br></br></xsl:if> </xsl:for-each></xsl:for-each> How could the code be changed to use a table?Replacing the br with tr doesn't work, because it must be closed and openend at the same line.
dooberry Posted April 12, 2006 Posted April 12, 2006 I don't think this needs much modification: <table><xsl:for-each select="ChineseWordList"> <xsl:for-each select="Word"> <xsl:sort select="PinYin"/> <xsl:if test="position() mod 20 = 1"> <tr> <xsl:if> <td> <xsl:value-of select="Chinese"/> <xsl:copy-of select="' '"/> </td> <xsl:if test="position() mod 20 = 0"> </tr> </xsl:if> </xsl:for-each></xsl:for-each><table> the only thing that might occur is an error because if the unmatched <tr> and </tr> tags in the xsl:if statements.Hope this helps, sorry if it doesn't :)Dooberry.
Volker Posted April 12, 2006 Author Posted April 12, 2006 the only thing that might occur is an error because if the unmatched <tr> and </tr> tags in the xsl:if statements.thx for the reply dooberry, the unmatched tr and /tr elements are the major point.At the moment i'm not aware of how to place them.Maybe i have to write something like:write tr, write first 20 elements and than attach the closing tr. continue this loop with the next 20 elements until all have been processed. My experience with xsl is not much , so i'm a bit lost finding a way moving thru the sorted nodetree this way.Volker
dooberry Posted April 12, 2006 Posted April 12, 2006 What about trying <xsl:value-of select="'<tr>'" /><xsl:value-of select="'</tr>'" /> instead?I'm wondering if these text values will work by not being part of the html in the stylesheet.I've used this technique before to tell xsl to use a text value in value-of instead of select a node value.I'll try it and see what the results are.As these
boen_robot Posted April 12, 2006 Posted April 12, 2006 What about trying<xsl:value-of select="'<tr>'" /><xsl:value-of select="'</tr>'" /> instead?I'm wondering if these text values will work by not being part of the html in the stylesheet.I've used this technique before to tell xsl to use a text value in value-of instead of select a node value.I'll try it and see what the results are.As these I already know the answer. It won't work, because "<" and ">" are invalid inside elements including atribute values. Replacing them with entities is going to make only plain text.Creating "invalid" XSLT code is what I think we can call the holy grail of XSLT .
dooberry Posted April 12, 2006 Posted April 12, 2006 I've cracked it but I've also found something odd with the position() function.here is something that worked: <xsl:template match="item"><xsl:for-each select="."> <td> <xsl:value-of select="." /> </td></xsl:for-each><xsl:if test="position() mod 4 = 0" ><tr /></xsl:if></xsl:template> As a programmer it doesn't seem logical that the position() function has to be outside the for-each statement.This works because when the expression evaluates to 0 the <tr /> is added which is a closed table row (a table row with nothing in it!!).This is a shortcut for <tr></tr> that would work in place of <tr /> in the above code.I knew I'd get it in the end All things meritorious are as difficult as they are rare!!Dooberry
Volker Posted April 12, 2006 Author Posted April 12, 2006 thx Dooberry, the knowledge about using <tr /> does it. It works.
Guest Vinz Posted April 14, 2006 Posted April 14, 2006 I've cracked it but I've also found something odd with the position() function.here is something that worked:<xsl:template match="item"><xsl:for-each select="."> <td> <xsl:value-of select="." /> </td></xsl:for-each><xsl:if test="position() mod 4 = 0" ><tr /></xsl:if></xsl:template> As a programmer it doesn't seem logical that the position() function has to be outside the for-each statement.This works because when the expression evaluates to 0 the <tr /> is added which is a closed table row (a table row with nothing in it!!).This is a shortcut for <tr></tr> that would work in place of <tr /> in the above code.I knew I'd get it in the end :)Dooberry <{POST_SNAPBACK}> It works but it seems to produce invalid HTML doesn't it?
boen_robot Posted April 20, 2006 Posted April 20, 2006 Unfortunatly, that's too true. I was just able to run Cold Fusion's XSLT processor and with this XML: <?xml version="1.0" encoding="windows-1251"?><?xml-stylesheet type="text/xsl" href="dictionary.xsl"?><Dictionary><Word> <Chinese>A</Chinese> <PinYin>B</PinYin></Word><Word> <Chinese>C</Chinese> <PinYin>D</PinYin></Word><Word> <Chinese>E</Chinese> <PinYin>F</PinYin></Word><Word> <Chinese>G</Chinese> <PinYin>H</PinYin></Word><Word> <Chinese>I</Chinese> <PinYin>J</PinYin></Word><Word> <Chinese>K</Chinese> <PinYin>L</PinYin></Word><Word> <Chinese>M</Chinese> <PinYin>N</PinYin></Word><Word> <Chinese>O</Chinese> <PinYin>P</PinYin></Word><Word> <Chinese>Q</Chinese> <PinYin>R</PinYin></Word><Word> <Chinese>S</Chinese> <PinYin>T</PinYin></Word><Word> <Chinese>U</Chinese> <PinYin>V</PinYin></Word><Word> <Chinese>W</Chinese> <PinYin>X</PinYin></Word><Word> <Chinese>Y</Chinese> <PinYin>Z</PinYin></Word><Word> <Chinese>1</Chinese> <PinYin>2</PinYin></Word><Word> <Chinese>3</Chinese> <PinYin>4</PinYin></Word><Word> <Chinese>5</Chinese> <PinYin>6</PinYin></Word><Word> <Chinese>7</Chinese> <PinYin>8</PinYin></Word><Word> <Chinese>9</Chinese> <PinYin>10</PinYin></Word><Word> <Chinese>11</Chinese> <PinYin>12</PinYin></Word><Word> <Chinese>13</Chinese> <PinYin>14</PinYin></Word></Dictionary> This XSLT <?xml version="1.0" encoding="windows-1251"?><!-- DWXMLSource="dictonary.xml" --><!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> <!ENTITY copy "©"> <!ENTITY reg "®"> <!ENTITY trade "™"> <!ENTITY mdash "—"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY pound "£"> <!ENTITY yen "¥"> <!ENTITY euro "€">]><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" encoding="windows-1251"doctype-public="-//W3C//DTD XHTML 1.1//EN" doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/><xsl:template match="/Dictionary"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/><title>Untitled Document</title><style type="text/css">td {border: 1px solid #000000;}tr {border: 1px solid #FF0000;}</style></head><body><table><xsl:apply-templates select="Word" /></table></body></html></xsl:template><xsl:template match="Word"><xsl:for-each select="."> <td> <xsl:value-of select="." /> </td></xsl:for-each><xsl:if test="position() mod 4 = 0" ><tr /></xsl:if></xsl:template></xsl:stylesheet> And this cfm <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta content="text/html; charset=windows-1251" http-equiv="Content-Type" /><title>Untitled Document</title><style type="text/css">td {border: 1px solid #000000;}tr {border: 1px solid #FF0000;}</style><META NAME="ColdFusionMXEdition" CONTENT="ColdFusion DevNet Edition - Not for Production Use."></head><body><table><td xmlns=""> A B</td><td> C D</td><td> E F</td><td> G H</td><td> I J</td><tr></tr><td> K L</td><td> M N</td><td> O P</td><td> Q R</td><td> S T</td><tr></tr><td> U V</td><td> W X</td><td> Y Z</td><td> 1 2</td><td> 3 4</td><tr></tr><td> 5 6</td><td> 7 8</td><td> 9 10</td><td> 11 12</td><td> 13 14</td><tr></tr></table></body></html> As you can see for yourself, it's all invalid.
Volker Posted April 21, 2006 Author Posted April 21, 2006 Hi,if i use this structure of xml: ...<Word> <Chinese>你</Chinese> <PinYin>nǐ</PinYin> <PinYinNumber>ni3</PinYinNumber> </Word> <Word> <Chinese>好</Chinese> <PinYin>hǎo</PinYin> <PinYinNumber>ha3o</PinYinNumber> </Word>... with this xslt: <table border="0" cellpadding="1" rules="all" width="100%"> <xsl:for-each select="ChineseWordList"> <xsl:for-each select="Word"> <xsl:sort select="PinYinNumber"/> <td><xsl:value-of select="Chinese"/></td> <xsl:if test="position() mod 8 = 0"><tr /></xsl:if> </xsl:for-each> </xsl:for-each> </table> I get the following result(values doesn't match the contents from the XML above, but ...). <table border="0" cellpadding="1" rules="all" width="100%"><td>爱人</td><td>班</td><td>班</td><td>帮助</td><td>包</td><td>爸爸</td><td>办公室</td><tr />...</table> which is just displayed perfectly inside IE or FireFox(Using XMLSpy).Volker
boen_robot Posted April 21, 2006 Posted April 21, 2006 That's what me and Vinz said actually. It displays correctly in both browsers, but technically speaking, it's not a valid XHTML output code. This is the only solution which you would have to stick with now, but if you're looking for a valid output, you should try to create something else as well.
boen_robot Posted April 24, 2006 Posted April 24, 2006 (edited) I must say I now feel both as a noob and a guru. A noob for my previous statement that insterting invalid code is like a holy grail. Guru, for discovering that holy grail . It's an element I avoid using. Who would have though how life saving <xsl:text> could be?!?! <?xml version="1.0" encoding="windows-1251"?><!-- DWXMLSource="dictonary.xml" --><!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> <!ENTITY copy "©"> <!ENTITY reg "®"> <!ENTITY trade "™"> <!ENTITY mdash "—"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY pound "£"> <!ENTITY yen "¥"> <!ENTITY euro "€">]><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" encoding="windows-1251"doctype-public="-//W3C//DTD XHTML 1.1//EN" doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/><xsl:template match="/Dictionary"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/><title>Untitled Document</title><style type="text/css">td {border: 1px solid #000000;}tr {border: 1px solid #FF0000;}.PinYin {text-align: right;}.Chinese {text-align: left;}</style></head><body><table><xsl:for-each select="Word"><xsl:variable name="columns">4</xsl:variable> <xsl:if test="position() mod $columns=1"> <xsl:text disable-output-escaping="yes"><tr></xsl:text> </xsl:if> <td> <span class="{local-name(Chinese)}"><xsl:value-of select="Chinese"/></span> <span class="{local-name(PinYin)}"><xsl:value-of select="PinYin"/></span> </td> <xsl:if test="position() mod $columns=0"> <xsl:text disable-output-escaping="yes"></tr></xsl:text> </xsl:if></xsl:for-each></table></body></html></xsl:template></xsl:stylesheet> Produces completely valid code . The only problem is that if ran directly by Firefox or Opera 9 Build 8219, you see plain text instead. That's actually a wrong behaviour I think, but still. If you parse it on the server side, it displays and comes valid in all browsers.Note that I've used the XML I provided in my second last post.Does anyone know how could I (or you by yourself) report this to both Opera and Mozilla?[edit]Reported to both Mozilla and Opera. Opera doesn't say anything yet It turned out Opera had a newer bild (8367) which now supports disable-output-escaping and as for Mozilla, this issue turned out to be a very frequently reported one and they don't intend on fixing it. See bug 98168 for details. In the mean time, I found another solution in the bug itself. Someone posted a "challenge" for the exact same idea here and one person was able to solve the issue. Here's the solution, adopted for this XML of course: <?xml version="1.0" encoding="windows-1251"?><!-- DWXMLSource="dictonary.xml" --><!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> <!ENTITY copy "©"> <!ENTITY reg "®"> <!ENTITY trade "™"> <!ENTITY mdash "—"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY pound "£"> <!ENTITY yen "¥"> <!ENTITY euro "€">]><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" encoding="windows-1251"doctype-public="-//W3C//DTD XHTML 1.1//EN" doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/><xsl:param name="group-size" select="4" /><xsl:template match="/Dictionary"><html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/> <title>Untitled Document</title> <style type="text/css"> <xsl:comment> td {border: 1px solid #000000;} tr {border: 1px solid #FF0000;} .Chinese {text-align: left;} .PinYin {text-align: right;} </xsl:comment> </style> </head> <body> <table> <xsl:apply-templates select="Word[(position() mod $group-size) = 1]" /> </table> </body> </html> </xsl:template><xsl:template match="Word"> <tr> <xsl:for-each select=". | following-sibling::Word[position() < $group-size]"> <td> <span class="Chinese"><xsl:value-of select="Chinese" /></span> <span class="PinYin"><xsl:value-of select="PinYin" /></span> </td> </xsl:for-each> </tr> </xsl:template></xsl:stylesheet> Stupid mozilla .[/edit] Edited April 25, 2006 by boen_robot
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now