git.iko.soy/typeable/pandoc
on master help sign in
fixes #1859 HTML Reader table parsing
b40d33bmb21
src/Text/Pandoc/Readers/HTML.hs+22−11
@@ -374,12 +374,20 @@ pTable = try $ do
374 caption <- option mempty $ pInTags "caption" inline <* skipMany pBlank
374 caption <- option mempty $ pInTags "caption" inline <* skipMany pBlank
375 -- TODO actually read these and take width information from them
375 -- TODO actually read these and take width information from them
376 widths' <- pColgroup <|> many pCol
376 widths' <- pColgroup <|> many pCol
377− head' <- option [] $ pOptInTag "thead" $ pInTags "tr" (pCell "th")
377+ let pTh = option [] $ pInTags "tr" (pCell "th")
378− skipMany pBlank
379− rows <- pOptInTag "tbody"
380− $ many1 $ try $ skipMany pBlank >> pInTags "tr" (pCell "td")
378+ pTr = try $ skipMany pBlank >> pInTags "tr" (pCell "td" <|> pCell "th")
381− skipMany pBlank
379+ pTBody = do pOptInTag "tbody" $ many1 pTr
380+ head'' <- pOptInTag "thead" pTh
381+ head' <- pOptInTag "tbody" $ do
382+ if null head''
383+ then pTh
384+ else return head''
385+ rowsLs <- many pTBody
386+ rows' <- pOptInTag "tfoot" $ many pTr
382 TagClose _ <- pSatisfy (~== TagClose "table")
387 TagClose _ <- pSatisfy (~== TagClose "table")
388+ let rows = (concat rowsLs) ++ rows'
389+ -- fail on empty table
390+ guard $ not $ null head' && null rows
383 let isSinglePlain x = case B.toList x of
391 let isSinglePlain x = case B.toList x of
384 [Plain _] -> True
392 [Plain _] -> True
385 _ -> False
393 _ -> False
@@ -624,14 +632,17 @@ pInTags tagtype parser = try $ do
624 pSatisfy (~== TagOpen tagtype [])
632 pSatisfy (~== TagOpen tagtype [])
625 mconcat <$> manyTill parser (pCloses tagtype <|> eof)
633 mconcat <$> manyTill parser (pCloses tagtype <|> eof)
626
634
635+-- parses p, preceeded by an optional opening tag
636+-- and followed by an optional closing tags
627−pOptInTag :: String -> TagParser a
637+pOptInTag :: String -> TagParser a -> TagParser a
628− -> TagParser a
629−pOptInTag tagtype parser = try $ do
638+pOptInTag tagtype p = try $ do
639+ skipMany pBlank
630− open <- option False (pSatisfy (~== TagOpen tagtype []) >> return True)
640+ optional $ pSatisfy (~== TagOpen tagtype [])
641+ skipMany pBlank
642+ x <- p
631 skipMany pBlank
643 skipMany pBlank
632− x <- parser
644+ optional $ pSatisfy (~== TagClose tagtype)
633 skipMany pBlank
645 skipMany pBlank
634− when open $ pCloses tagtype
635 return x
646 return x
636
647
637pCloses :: String -> TagParser ()
648pCloses :: String -> TagParser ()
tests/html-reader.html+247
@@ -433,6 +433,7 @@ An e-mail address: nobody [at] nowhere.net<blockquote>
433<p>text<em> Leading spaces</em></p>
433<p>text<em> Leading spaces</em></p>
434<p><em>Trailing spaces </em>text</p>
434<p><em>Trailing spaces </em>text</p>
435<h1>Tables</h1>
435<h1>Tables</h1>
436+<h2>Tables with Headers</h2>
436<table>
437<table>
437 <tr>
438 <tr>
438 <th>X</th>
439 <th>X</th>
@@ -450,5 +451,251 @@ An e-mail address: nobody [at] nowhere.net<blockquote>
450 <td>6</td>
451 <td>6</td>
451 </tr>
452 </tr>
452</table>
453</table>
454+<hr />
455+<table>
456+ <thead>
457+ <tr>
458+ <th>X</th>
459+ <th>Y</th>
460+ <th>Z</th>
461+ </tr>
462+ </thead>
463+ <tbody>
464+ <tr>
465+ <td>1</td>
466+ <td>2</td>
467+ <td>3</td>
468+ </tr>
469+ <tr>
470+ <td>4</td>
471+ <td>5</td>
472+ <td>6</td>
473+ </tr>
474+ </tbody>
475+</table>
476+<hr />
477+<table>
478+ <thead>
479+ <tr>
480+ <th>X</th>
481+ <th>Y</th>
482+ <th>Z</th>
483+ </tr>
484+ </thead>
485+ <tbody>
486+ <tr>
487+ <th>1</th>
488+ <td>2</td>
489+ <td>3</td>
490+ </tr>
491+ <tr>
492+ <th>4</th>
493+ <td>5</td>
494+ <td>6</td>
495+ </tr>
496+ </tbody>
497+</table>
498+<hr />
499+<table>
500+ <thead>
501+ <tr>
502+ <th>X</th>
503+ <th>Y</th>
504+ <th>Z</th>
505+ </tr>
506+ </thead>
507+ <tbody>
508+ <tr>
509+ <th>1</th>
510+ <td>2</td>
511+ <td>3</td>
512+ </tr>
513+ </tbody>
514+ <tfoot>
515+ <tr>
516+ <th>4</th>
517+ <td>5</td>
518+ <td>6</td>
519+ </tr>
520+ </tfoot>
521+</table>
522+<hr />
523+<table>
524+ <tr>
525+ <th>X</th>
526+ <th>Y</th>
527+ <th>Z</th>
528+ </tr>
529+ <tr>
530+ <th>1</th>
531+ <th>2</th>
532+ <th>3</th>
533+ </tr>
534+ <tr>
535+ <td>4</td>
536+ <td>5</td>
537+ <td>6</td>
538+ </tr>
539+</table>
540+<hr />
541+<table>
542+ <tbody>
543+ <tr>
544+ <th>X</th>
545+ <th>Y</th>
546+ <th>Z</th>
547+ </tr>
548+ <tr>
549+ <td>1</td>
550+ <td>2</td>
551+ <td>3</td>
552+ </tr>
553+ <tr>
554+ <td>4</td>
555+ <td>5</td>
556+ <td>6</td>
557+ </tr>
558+ </tbody>
559+</table>
560+<hr />
561+<table>
562+ <thead>
563+ </thead>
564+ <tbody>
565+ <tr>
566+ <th>X</th>
567+ <th>Y</th>
568+ <th>Z</th>
569+ </tr>
570+ <tr>
571+ <td>1</td>
572+ <td>2</td>
573+ <td>3</td>
574+ </tr>
575+ <tr>
576+ <td>4</td>
577+ <td>5</td>
578+ <td>6</td>
579+ </tr>
580+ </tbody>
581+</table>
582+<hr />
583+<table>
584+ <thead>
585+ <tr>
586+ <th>X</th>
587+ <th>Y</th>
588+ <th>Z</th>
589+ </tr>
590+ </thead>
591+ <tbody>
592+ <tr>
593+ <td>1</td>
594+ <td>2</td>
595+ <td>3</td>
596+ </tr>
597+ </tbody>
598+ <tbody>
599+ <tr>
600+ <td>4</td>
601+ <td>5</td>
602+ <td>6</td>
603+ </tr>
604+ </tbody>
605+</table>
606+<hr />
607+<table>
608+ <thead>
609+ <tr>
610+ <th>X</th>
611+ <th>Y</th>
612+ <th>Z</th>
613+ </tr>
614+ </thead>
615+ <tbody>
616+ <tr>
617+ <td>1</td>
618+ <td><p>2</p></td>
619+ <td>3</td>
620+ </tr>
621+ </tbody>
622+ <tbody>
623+ <tr>
624+ <td>4</td>
625+ <td>5</td>
626+ <td>6</td>
627+ </tr>
628+ </tbody>
629+</table>
630+<h2>Tables without Headers</h2>
631+<table>
632+ <tbody>
633+ <tr>
634+ <td>1</td>
635+ <td>2</td>
636+ <td>3</td>
637+ </tr>
638+ <tr>
639+ <td>4</td>
640+ <td>5</td>
641+ <td>6</td>
642+ </tr>
643+ </tbody>
644+</table>
645+<hr />
646+<table>
647+ <tr>
648+ <td>1</td>
649+ <td>2</td>
650+ <td>3</td>
651+ </tr>
652+ <tr>
653+ <td>4</td>
654+ <td>5</td>
655+ <td>6</td>
656+ </tr>
657+</table>
658+<hr />
659+<table>
660+ <thead>
661+ </thead>
662+ <tbody>
663+ <tr>
664+ <td>1</td>
665+ <td>2</td>
666+ <td>3</td>
667+ </tr>
668+ <tr>
669+ <td>4</td>
670+ <td>5</td>
671+ <td>6</td>
672+ </tr>
673+ </tbody>
674+</table>
675+<hr />
676+<table>
677+ <tbody>
678+ <tr>
679+ <td>1</td>
680+ <td>2</td>
681+ <td>3</td>
682+ </tr>
683+ </tbody>
684+ <tfoot>
685+ <tr>
686+ <td>4</td>
687+ <td>5</td>
688+ <td>6</td>
689+ </tr>
690+ </tfoot>
691+</table>
692+<h2>Empty Tables</h2>
693+<p>This section should be empty.</p>
694+<table>
695+ <tbody>
696+ </tbody>
697+</table>
698+<table>
699+</table>
453</body>
700</body>
454</html>
701</html>
tests/html-reader.native+128−1
@@ -311,6 +311,7 @@ Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("titl
311,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
311,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
312,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
312,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
313,Header 1 ("",[],[]) [Str "Tables"]
313,Header 1 ("",[],[]) [Str "Tables"]
314+,Header 2 ("",[],[]) [Str "Tables",Space,Str "with",Space,Str "Headers"]
314,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
315,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
315 [[Plain [Str "X"]]
316 [[Plain [Str "X"]]
316 ,[Plain [Str "Y"]]
317 ,[Plain [Str "Y"]]
@@ -320,4 +321,130 @@ Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("titl
320 ,[Plain [Str "3"]]]
321 ,[Plain [Str "3"]]]
321 ,[[Plain [Str "4"]]
322 ,[[Plain [Str "4"]]
322 ,[Plain [Str "5"]]
323 ,[Plain [Str "5"]]
323− ,[Plain [Str "6"]]]]]
324+ ,[Plain [Str "6"]]]]
325+,HorizontalRule
326+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
327+ [[Plain [Str "X"]]
328+ ,[Plain [Str "Y"]]
329+ ,[Plain [Str "Z"]]]
330+ [[[Plain [Str "1"]]
331+ ,[Plain [Str "2"]]
332+ ,[Plain [Str "3"]]]
333+ ,[[Plain [Str "4"]]
334+ ,[Plain [Str "5"]]
335+ ,[Plain [Str "6"]]]]
336+,HorizontalRule
337+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
338+ [[Plain [Str "X"]]
339+ ,[Plain [Str "Y"]]
340+ ,[Plain [Str "Z"]]]
341+ [[[Plain [Str "1"]]
342+ ,[Plain [Str "2"]]
343+ ,[Plain [Str "3"]]]
344+ ,[[Plain [Str "4"]]
345+ ,[Plain [Str "5"]]
346+ ,[Plain [Str "6"]]]]
347+,HorizontalRule
348+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
349+ [[Plain [Str "X"]]
350+ ,[Plain [Str "Y"]]
351+ ,[Plain [Str "Z"]]]
352+ [[[Plain [Str "1"]]
353+ ,[Plain [Str "2"]]
354+ ,[Plain [Str "3"]]]
355+ ,[[Plain [Str "4"]]
356+ ,[Plain [Str "5"]]
357+ ,[Plain [Str "6"]]]]
358+,HorizontalRule
359+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
360+ [[Plain [Str "X"]]
361+ ,[Plain [Str "Y"]]
362+ ,[Plain [Str "Z"]]]
363+ [[[Plain [Str "1"]]
364+ ,[Plain [Str "2"]]
365+ ,[Plain [Str "3"]]]
366+ ,[[Plain [Str "4"]]
367+ ,[Plain [Str "5"]]
368+ ,[Plain [Str "6"]]]]
369+,HorizontalRule
370+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
371+ [[Plain [Str "X"]]
372+ ,[Plain [Str "Y"]]
373+ ,[Plain [Str "Z"]]]
374+ [[[Plain [Str "1"]]
375+ ,[Plain [Str "2"]]
376+ ,[Plain [Str "3"]]]
377+ ,[[Plain [Str "4"]]
378+ ,[Plain [Str "5"]]
379+ ,[Plain [Str "6"]]]]
380+,HorizontalRule
381+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
382+ [[Plain [Str "X"]]
383+ ,[Plain [Str "Y"]]
384+ ,[Plain [Str "Z"]]]
385+ [[[Plain [Str "1"]]
386+ ,[Plain [Str "2"]]
387+ ,[Plain [Str "3"]]]
388+ ,[[Plain [Str "4"]]
389+ ,[Plain [Str "5"]]
390+ ,[Plain [Str "6"]]]]
391+,HorizontalRule
392+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
393+ [[Plain [Str "X"]]
394+ ,[Plain [Str "Y"]]
395+ ,[Plain [Str "Z"]]]
396+ [[[Plain [Str "1"]]
397+ ,[Plain [Str "2"]]
398+ ,[Plain [Str "3"]]]
399+ ,[[Plain [Str "4"]]
400+ ,[Plain [Str "5"]]
401+ ,[Plain [Str "6"]]]]
402+,HorizontalRule
403+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.3333333333333333,0.3333333333333333,0.3333333333333333]
404+ [[Plain [Str "X"]]
405+ ,[Plain [Str "Y"]]
406+ ,[Plain [Str "Z"]]]
407+ [[[Plain [Str "1"]]
408+ ,[Para [Str "2"]]
409+ ,[Plain [Str "3"]]]
410+ ,[[Plain [Str "4"]]
411+ ,[Plain [Str "5"]]
412+ ,[Plain [Str "6"]]]]
413+,Header 2 ("",[],[]) [Str "Tables",Space,Str "without",Space,Str "Headers"]
414+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
415+ []
416+ [[[Plain [Str "1"]]
417+ ,[Plain [Str "2"]]
418+ ,[Plain [Str "3"]]]
419+ ,[[Plain [Str "4"]]
420+ ,[Plain [Str "5"]]
421+ ,[Plain [Str "6"]]]]
422+,HorizontalRule
423+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
424+ []
425+ [[[Plain [Str "1"]]
426+ ,[Plain [Str "2"]]
427+ ,[Plain [Str "3"]]]
428+ ,[[Plain [Str "4"]]
429+ ,[Plain [Str "5"]]
430+ ,[Plain [Str "6"]]]]
431+,HorizontalRule
432+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
433+ []
434+ [[[Plain [Str "1"]]
435+ ,[Plain [Str "2"]]
436+ ,[Plain [Str "3"]]]
437+ ,[[Plain [Str "4"]]
438+ ,[Plain [Str "5"]]
439+ ,[Plain [Str "6"]]]]
440+,HorizontalRule
441+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
442+ []
443+ [[[Plain [Str "1"]]
444+ ,[Plain [Str "2"]]
445+ ,[Plain [Str "3"]]]
446+ ,[[Plain [Str "4"]]
447+ ,[Plain [Str "5"]]
448+ ,[Plain [Str "6"]]]]
449+,Header 2 ("",[],[]) [Str "Empty",Space,Str "Tables"]
450+,Para [Str "This",Space,Str "section",Space,Str "should",Space,Str "be",Space,Str "empty."]]