html table with pollen #31

Closed
opened 10 years ago by ChristianSch · 10 comments
ChristianSch commented 10 years ago (Migrated from github.com)

Hi.

I’m having a hard time with more complex tags like table, trow and tdata (let alone optional thead and/or tfoot). This is the code for my custom table function:

(define (table . rows)
    `(table ,(map (lambda (row)
        `(trow ,(map
            (lambda (data) `(tdata ,data))
            (string-split row ","))))
    rows)))

And this is the original code for the table:

◊table{
  1,un
  2,deux
  3,trois
  4,quartre
  5,cenq
  6,six
  7,sept
  8,huit
  9,neuff
  10,dix
  11,ounze
  12,dounze
}

The outcome looks like this:

decode-elements: contract violation
  expected: txexpr-elements?
  given: '((h1 "Vorlesung 1") "\n" "\n" (h2 "Vorstellung") "\n" "\n" "Je suis de Goslar. " (span ((class "translation")) "Ich bin/komme aus Goslar.") "\n" "Et toi? " (span ((class "translation")) "Und du?") "\n" "Je m'appelle Christian. " (span ((class "translation")) "Ich bin/heiße Christian.") "\n" "\n" (h2 "Das französische Alphabet") "\n" "\n" "Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Maecenas faucibus mollis interdum. Integer posuere erat a ante venenatis dapibus posuere velit aliquet." "\n" "\n" (div ((class "box")) (h2 "Die Zahlen bis 12") "\n" " " (table ((trow ((tdata "1") (tdata "un"))) (trow ((tdata "\n"))) (trow ((tdata "2") (tdata "deux"))) (trow ((tdata "\n"))) (trow ((tdata "3") (tdata "trois"))) (trow ((tdata "\n"))) (trow ((tdata "4") (tdata "quartre"))) (trow ((tdata "\n"))) (trow ((tdata "5") (tdata "cenq"))) (trow ((t...
  in: the 1st argument of
      (->*
       (txexpr-elements?)
       (#:block-txexpr-proc
        (-> block-txexpr? xexpr?)
        #:cdata-proc
        (-> cdata? xexpr?)
        #:exclude-tags
        (listof symbol?)
        #:inline-txexpr-proc
        (-> txexpr? xexpr?)
        #:string-proc
        (-> string? xexpr?)
        #:symbol-proc
        (-> symbol? xexpr?)
        #:txexpr-attrs-proc
        (-> txexpr-attrs? txexpr-attrs?)
        #:txexpr-elements-proc
        (-> txexpr-elements? txexpr-elements?)
        #:txexpr-tag-proc
        (-> txexpr-tag? txexpr-tag?)
        #:valid-char-proc
        (-> valid-char? xexpr?))
       txexpr-elements?)
  contract from: <pkgs>/pollen/decode.rkt
  blaming: /Users/cocoanaut/Copy/Uni/WS1415/Franzoesisch/Skript/directory-require.rkt
   (assuming the contract is correct)
  at: <pkgs>/pollen/decode.rkt:70.26
(table ((trow ((tdata "1") (tdata "un"))) (trow ((tdata "\n"))) (trow ((tdata "2") (tdata "deux"))) (trow ((tdata "\n"))) (trow ((tdata "3") (tdata "trois"))) (trow ((tdata "\n"))) (trow ((tdata "4") (tdata "quartre"))) (trow ((tdata "\n"))) (trow ((tdata "5") (tdata "cenq"))) (trow ((t...

Almost! But I can’t get it working without having the double quotes. Any thoughts on this?

Hi. I’m having a hard time with more complex tags like table, trow and tdata (let alone optional thead and/or tfoot). This is the code for my custom `table` function: ``` (define (table . rows) `(table ,(map (lambda (row) `(trow ,(map (lambda (data) `(tdata ,data)) (string-split row ",")))) rows))) ``` And this is the original code for the table: ``` ◊table{ 1,un 2,deux 3,trois 4,quartre 5,cenq 6,six 7,sept 8,huit 9,neuff 10,dix 11,ounze 12,dounze } ``` The outcome looks like this: ``` decode-elements: contract violation expected: txexpr-elements? given: '((h1 "Vorlesung 1") "\n" "\n" (h2 "Vorstellung") "\n" "\n" "Je suis de Goslar. " (span ((class "translation")) "Ich bin/komme aus Goslar.") "\n" "Et toi? " (span ((class "translation")) "Und du?") "\n" "Je m'appelle Christian. " (span ((class "translation")) "Ich bin/heiße Christian.") "\n" "\n" (h2 "Das französische Alphabet") "\n" "\n" "Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Maecenas faucibus mollis interdum. Integer posuere erat a ante venenatis dapibus posuere velit aliquet." "\n" "\n" (div ((class "box")) (h2 "Die Zahlen bis 12") "\n" " " (table ((trow ((tdata "1") (tdata "un"))) (trow ((tdata "\n"))) (trow ((tdata "2") (tdata "deux"))) (trow ((tdata "\n"))) (trow ((tdata "3") (tdata "trois"))) (trow ((tdata "\n"))) (trow ((tdata "4") (tdata "quartre"))) (trow ((tdata "\n"))) (trow ((tdata "5") (tdata "cenq"))) (trow ((t... in: the 1st argument of (->* (txexpr-elements?) (#:block-txexpr-proc (-> block-txexpr? xexpr?) #:cdata-proc (-> cdata? xexpr?) #:exclude-tags (listof symbol?) #:inline-txexpr-proc (-> txexpr? xexpr?) #:string-proc (-> string? xexpr?) #:symbol-proc (-> symbol? xexpr?) #:txexpr-attrs-proc (-> txexpr-attrs? txexpr-attrs?) #:txexpr-elements-proc (-> txexpr-elements? txexpr-elements?) #:txexpr-tag-proc (-> txexpr-tag? txexpr-tag?) #:valid-char-proc (-> valid-char? xexpr?)) txexpr-elements?) contract from: <pkgs>/pollen/decode.rkt blaming: /Users/cocoanaut/Copy/Uni/WS1415/Franzoesisch/Skript/directory-require.rkt (assuming the contract is correct) at: <pkgs>/pollen/decode.rkt:70.26 ``` ``` (table ((trow ((tdata "1") (tdata "un"))) (trow ((tdata "\n"))) (trow ((tdata "2") (tdata "deux"))) (trow ((tdata "\n"))) (trow ((tdata "3") (tdata "trois"))) (trow ((tdata "\n"))) (trow ((tdata "4") (tdata "quartre"))) (trow ((tdata "\n"))) (trow ((tdata "5") (tdata "cenq"))) (trow ((t... ``` Almost! But I can’t get it working without having the double quotes. Any thoughts on this?
mbutterick commented 10 years ago (Migrated from github.com)

You’ve almost got it.

When you're building a tag with quasiquote, and you have a list of elements that you want to put inside the tag, you need to use unquote splicing ,@ rather than plain unquote ,. Unquote will put your elements inside the tag as a nested list, whereas unquote splicing will merge them with the tag, like so:

`(tag ,(list "one" "two" "three")) ; unquote with list
> '(tag ("one" "two" "three")) ; wrong result: list is nested
`(tag ,@(list "one" "two" "three")) ; unquote splicing with list
> '(tag "one" "two" "three") ; right result: list is merged

Thus, your function should use unquote splicing:

(define (table . rows)
    `(table ,@(map (lambda (row) ; unquote splicing added here
        `(trow ,@(map ; unquote splicing added here
            (lambda (data) `(tdata ,data))
            (string-split row ","))))
    rows)))

Keep in mind that the the arguments passed to table are a list of strings that also include the linebreaks ("\n") within the text block. So if you don't want those to appear in your table, you can filter them out of rows. The pollen/decode module has a function called whitespace? for this purpose:

(require pollen/decode) ; makes `whitespace?` available
(define (table . rows)
    `(table ,@(map (lambda (row) 
        `(trow ,@(map 
            (lambda (data) `(tdata ,data))
            (string-split row ","))))
    (filter-not whitespace? rows)))) ; removes whitespace elements from `rows`

Alternatively, rather than filtering the list, you could also recombine the rows into a single string with string-append* and then string-split on \n, with identical results:

(define (table . rows)
    `(table ,@(map (lambda (row)
        `(trow ,@(map
            (lambda (data) `(tdata ,data))
            (string-split row ","))))
    (string-split (string-append* rows) "\n"))))
You’ve almost got it. When you're building a tag with quasiquote, and you have a list of elements that you want to put inside the tag, you need to use unquote splicing `,@` rather than plain unquote `,`. Unquote will put your elements inside the tag as a nested list, whereas unquote splicing will merge them with the tag, like so: ``` racket `(tag ,(list "one" "two" "three")) ; unquote with list > '(tag ("one" "two" "three")) ; wrong result: list is nested `(tag ,@(list "one" "two" "three")) ; unquote splicing with list > '(tag "one" "two" "three") ; right result: list is merged ``` Thus, your function should use unquote splicing: ``` racket (define (table . rows) `(table ,@(map (lambda (row) ; unquote splicing added here `(trow ,@(map ; unquote splicing added here (lambda (data) `(tdata ,data)) (string-split row ",")))) rows))) ``` Keep in mind that the the arguments passed to `table` are a list of strings that also include the linebreaks (`"\n"`) within the text block. So if you don't want those to appear in your table, you can filter them out of `rows`. The `pollen/decode` module has a function called `whitespace?` for this purpose: ``` racket (require pollen/decode) ; makes `whitespace?` available (define (table . rows) `(table ,@(map (lambda (row) `(trow ,@(map (lambda (data) `(tdata ,data)) (string-split row ",")))) (filter-not whitespace? rows)))) ; removes whitespace elements from `rows` ``` Alternatively, rather than filtering the list, you could also recombine the `rows` into a single string with `string-append*` and then `string-split` on `\n`, with identical results: ``` racket (define (table . rows) `(table ,@(map (lambda (row) `(trow ,@(map (lambda (data) `(tdata ,data)) (string-split row ",")))) (string-split (string-append* rows) "\n")))) ```
ChristianSch commented 10 years ago (Migrated from github.com)

Great, thanks for your help! One problem still exists, though. The table tag (

) gets printed out after the rows. What causes this behavior? I don't really have any idea what causes this.

Great, thanks for your help! One problem still exists, though. The table tag (<table></table>) gets printed out after the rows. What causes this behavior? I don't really have any idea what causes this.
mbutterick commented 10 years ago (Migrated from github.com)

Can you explain how you trigger this behavior? When I run your code in the Pollen server I get the right result:

<html><head><meta charset="UTF-8" /></head><body>
<root><table>
<trow><tdata>1</tdata><tdata>un</tdata></trow>
<trow><tdata>2</tdata><tdata>deux</tdata></trow>
 ... 
</table></root>
</body></html>
Can you explain how you trigger this behavior? When I run your code in the Pollen server I get the right result: ``` html <html><head><meta charset="UTF-8" /></head><body> <root><table> <trow><tdata>1</tdata><tdata>un</tdata></trow> <trow><tdata>2</tdata><tdata>deux</tdata></trow> ... </table></root> </body></html> ```
ChristianSch commented 10 years ago (Migrated from github.com)

Please see here: https://github.com/ChristianSch/french-script
I fiddled around a bit and even the minimal example lecture4.html.pm turns out like this: https://gist.github.com/ChristianSch/f25b320410e6c48d1d68

Please see here: https://github.com/ChristianSch/french-script I fiddled around a bit and even the minimal example `lecture4.html.pm` turns out like this: https://gist.github.com/ChristianSch/f25b320410e6c48d1d68
mbutterick commented 10 years ago (Migrated from github.com)

Thank you for sharing your sample project. I'm afraid I can't reproduce your problem on OS X — DrRacket shows the correct X-expression when running your lecture4.html.pm:

'(root (h1 "Vorlesung 4") (table (trow (tdata "1") (tdata "2") (tdata "3")) 
(trow (tdata "a") (tdata "b") (tdata "c"))))

And Chrome, Opera, Safari, and Firefox all show the correct HTML, with the table tag wrapping the rows:

<div class="content">
<root><h1>Vorlesung 4</h1>
<table>
<trow><tdata>1</tdata><tdata>2</tdata><tdata>3</tdata></trow>
<trow><tdata>a</tdata><tdata>b</tdata><tdata>c</tdata></trow>
</table></root>
</div>

What platform / browser is triggering the problem for you?

Thank you for sharing your sample project. I'm afraid I can't reproduce your problem on OS X — DrRacket shows the correct X-expression when running your `lecture4.html.pm`: ``` racket '(root (h1 "Vorlesung 4") (table (trow (tdata "1") (tdata "2") (tdata "3")) (trow (tdata "a") (tdata "b") (tdata "c")))) ``` And Chrome, Opera, Safari, and Firefox all show the correct HTML, with the `table` tag wrapping the rows: ``` html <div class="content"> <root><h1>Vorlesung 4</h1> <table> <trow><tdata>1</tdata><tdata>2</tdata><tdata>3</tdata></trow> <trow><tdata>a</tdata><tdata>b</tdata><tdata>c</tdata></trow> </table></root> </div> ``` What platform / browser is triggering the problem for you?
ChristianSch commented 10 years ago (Migrated from github.com)

I’m using Racket 6.1.1 on OS X Yosemite with Safari 8. I testet it with Firefox 33.1.1, Chromium 39.0.2149.0 and curl. Guess what works as expected? …
I’ve never experienced something similar. This is weird.

$ curl http://localhost:8080/lecture4.html
<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8">
                <title>Französisch für den Beruf I: Vorlesung 4</title>

                <!-- Rosario Google Web Fonts import -->
                <link href='http://fonts.googleapis.com/css?family=Rosario:400,400italic,700,700italic' rel='stylesheet' type='text/css'>

                <link rel="stylesheet" type="text/css" media="all" href="styles.css" />
        </head>
        <body>
        <header>
                <div class="nav">
                        <!-- previous page -->
                        <div class="nav-prev">← <a href="lecture3.html">Vorlesung 3</a></div>

                        <!-- next page -->

                </div>
        </header><!-- /header -->
        <div class="content">
                <root><h1>Vorlesung 4</h1><table><trow><tdata>1</tdata><tdata>2</tdata><tdata>3</tdata></trow><trow><tdata>a</tdata><tdata>b</tdata><tdata>c</tdata></trow></table></root>
        </div>
        </body>
</html>

It seems that I have to fiddle a bit. Any tips about debugging this with pollen especially?

I’m using Racket 6.1.1 on OS X Yosemite with Safari 8. I testet it with Firefox 33.1.1, Chromium 39.0.2149.0 and curl. Guess what works as expected? … I’ve never experienced something similar. This is weird. ``` $ curl http://localhost:8080/lecture4.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Französisch für den Beruf I: Vorlesung 4</title> <!-- Rosario Google Web Fonts import --> <link href='http://fonts.googleapis.com/css?family=Rosario:400,400italic,700,700italic' rel='stylesheet' type='text/css'> <link rel="stylesheet" type="text/css" media="all" href="styles.css" /> </head> <body> <header> <div class="nav"> <!-- previous page --> <div class="nav-prev">← <a href="lecture3.html">Vorlesung 3</a></div> <!-- next page --> </div> </header><!-- /header --> <div class="content"> <root><h1>Vorlesung 4</h1><table><trow><tdata>1</tdata><tdata>2</tdata><tdata>3</tdata></trow><trow><tdata>a</tdata><tdata>b</tdata><tdata>c</tdata></trow></table></root> </div> </body> </html> ``` It seems that I have to fiddle a bit. Any tips about debugging this with pollen especially?
mbutterick commented 10 years ago (Migrated from github.com)

I've occasionally seen behavior like this during development. I believe it has to do with the browser getting confused about what to do with the root tag. Keep in mind that root is not a block element in HTML — it's an unspecified name, so by default, the browser treats it as an inline element. And inline elements aren't allowed to contain block elements (like h1 and table). Even if your CSS makes root a block element (with display: block), the browser will sometimes do the right thing, sometimes not.

You may ask, “why not use a name that is an HTML block tag for the root node, like div?” The answer is that Pollen is designed to be output-agnostic, and that would bind it too closely to HTML.

But there is a solution. Look at the extra options of the ->html function in the pollen/decode module, which will let you change root to something else. So instead of this:

<div class="content">
◊->html[doc]
</div>

You could write this:

(->html #:tag 'div #:attrs '((class "content")) doc)

This will get rid of the root tag and automatically generate the <div class="content"> ... </div>.

I've occasionally seen behavior like this during development. I believe it has to do with the browser getting confused about what to do with the `root` tag. Keep in mind that `root` is not a block element in HTML — it's an unspecified name, so by default, the browser treats it as an inline element. And inline elements aren't allowed to contain block elements (like `h1` and `table`). Even if your CSS makes `root` a block element (with `display: block`), the browser will sometimes do the right thing, sometimes not. You may ask, “why not use a name that **is** an HTML block tag for the `root` node, like `div`?” The answer is that Pollen is designed to be output-agnostic, and that would bind it too closely to HTML. But there is a solution. Look at the [extra options of the `->html` function](http://pkg-build.racket-lang.org/doc/pollen/Template.html#%28def._%28%28lib._pollen%2Ftemplate..rkt%29._-~3ehtml%29%29) in the `pollen/decode` module, which will let you change `root` to something else. So instead of this: ``` html <div class="content"> ◊->html[doc] </div> ``` You could write this: ``` racket ◊(->html #:tag 'div #:attrs '((class "content")) doc) ``` This will get rid of the `root` tag and automatically generate the `<div class="content"> ... </div>`.
ChristianSch commented 10 years ago (Migrated from github.com)

I changed the code as you suggested but the problem remains. Funny thing tho, if I use a p tag instead of table it works. Any ideas how this could happen? (Update didn’t help.)

Thanks for the detailed explanation. I totally get the idea behind it and it’s ok as long as I can generate valid html like you just explained.

I changed the code as you suggested but the problem remains. Funny thing tho, if I use a p tag instead of table it works. Any ideas how this could happen? (Update didn’t help.) Thanks for the detailed explanation. I totally get the idea behind it and it’s ok as long as I can generate valid html like you just explained.
ChristianSch commented 10 years ago (Migrated from github.com)

Got it. It was completely my fault. The weird behavior was caused by using trow and tdata instead of tr and td. Sorry for any inconveniences.

Got it. It was completely my fault. The weird behavior was caused by using `trow` and `tdata` instead of `tr` and `td`. Sorry for any inconveniences.
mbutterick commented 9 years ago (Migrated from github.com)

Glad you found the source of the problem. Same idea, however — because trow and tdata are not standard HTML tags, they were being treated as inline elements, not table-row and and table-cell elements, and the browser was parsing the DOM erratically.

Glad you found the source of the problem. Same idea, however — because `trow` and `tdata` are not standard HTML tags, they were being treated as inline elements, not table-row and and table-cell elements, and the browser was parsing the DOM erratically.
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: mbutterick/pollen#31
Loading…
There is no content yet.