diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index ab8e8ef93..eaf13b7da 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -30,6 +32,7 @@ module Text.Pandoc.Writers.HTML (
import Control.Monad.State.Strict
import Data.Char (ord)
import Data.List (intercalate, intersperse, partition, delete, (\\))
+import Data.List.NonEmpty (NonEmpty((:|)))
import Data.Maybe (fromMaybe, isJust, isNothing, mapMaybe)
import qualified Data.Set as Set
import Data.Text (Text)
@@ -53,6 +56,7 @@ import Text.Pandoc.Templates (renderTemplate)
import Text.Pandoc.Walk
import Text.Pandoc.Writers.Math
import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Writers.Tables
import Text.Pandoc.XML (escapeStringForXML, fromEntities, toEntities,
html5Attributes, html4Attributes, rdfaAttributes)
import qualified Text.Blaze.XHtml5 as H5
@@ -899,39 +903,33 @@ blockToHtml opts (DefinitionList lst) = do
return $ mconcat $ nl opts : term' : nl opts :
intersperse (nl opts) defs') lst
defList opts contents
-blockToHtml opts (Table attr blkCapt specs thead tbody tfoot) = do
- let (capt, aligns, widths, headers, rows') = toLegacyTable blkCapt specs thead tbody tfoot
- captionDoc <- if null capt
- then return mempty
- else do
- cs <- inlineListToHtml opts capt
- return $ H.caption cs >> nl opts
- html5 <- gets stHtml5
- let percent w = show (truncate (100*w) :: Integer) <> "%"
- let coltags = if all (== 0.0) widths
- then mempty
- else do
- H.colgroup $ do
- nl opts
- mapM_ (\w -> do
- if html5
- then H.col ! A.style (toValue $ "width: " <>
- percent w)
- else H.col ! A.width (toValue $ percent w)
- nl opts) widths
- nl opts
- head' <- if all null headers
- then return mempty
- else do
- contents <- tableRowToHtml opts aligns 0 headers
- return $ H.thead (nl opts >> contents) >> nl opts
- body' <- liftM (\x -> H.tbody (nl opts >> mconcat x)) $
- zipWithM (tableRowToHtml opts aligns) [1..] rows'
+blockToHtml opts (Table attr caption colspecs thead tbody tfoot) =
+ tableToHtml opts (toAnnTable attr caption colspecs thead tbody tfoot)
+
+tableToHtml :: PandocMonad m
+ => WriterOptions
+ -> AnnTable
+ -> StateT WriterState m Html
+tableToHtml opts (AnnTable attr caption colspecs thead tbodies _tfoot) = do
+ captionDoc <- case caption of
+ Caption _ [] -> return mempty
+ Caption _ longCapt -> do
+ cs <- blockListToHtml opts longCapt
+ return $ do
+ H.caption cs
+ nl opts
+ coltags <- colSpecListToHtml opts colspecs
+ head' <- tableHeadToHtml opts thead
+ body' <- mconcat <$> mapM (tableBodyToHtml opts) tbodies
let (ident,classes,kvs) = attr
-- When widths of columns are < 100%, we need to set width for the whole
-- table, or some browsers give us skinny columns with lots of space
-- between:
- let totalWidth = sum widths
+ -- let totalWidth = sum widths
+ let colWidth = \case
+ ColWidth d -> d
+ ColWidthDefault -> 0
+ let totalWidth = sum . map (colWidth . snd) $ colspecs
let attr' = case lookup "style" kvs of
Nothing | totalWidth < 1 && totalWidth > 0
-> (ident,classes, ("style","width:" <>
@@ -939,56 +937,180 @@ blockToHtml opts (Table attr blkCapt specs thead tbody tfoot) = do
<> "%;"):kvs)
_ -> attr
addAttrs opts attr' $ H.table $
- nl opts >> captionDoc >> coltags >> head' >> body' >> nl opts
+ nl opts *> captionDoc *> coltags *> head' *> body' *> nl opts
+
+tableBodyToHtml :: PandocMonad m
+ => WriterOptions
+ -> AnnTableBody
+ -> StateT WriterState m Html
+tableBodyToHtml opts (AnnTableBody _attr _rowHeadCols _intm rows) =
+ H.tbody <$> bodyRowsToHtml opts rows
+
+tableHeadToHtml :: PandocMonad m
+ => WriterOptions
+ -> AnnTableHead
+ -> StateT WriterState m Html
+tableHeadToHtml opts (AnnTableHead attr rows) =
+ if null rows || all isEmptyRow rows
+ then return mempty
+ else do
+ contents <- headerRowsToHtml opts rows
+ headElement <- addAttrs opts attr $ H.thead contents
+ return $ do
+ headElement
+ nl opts
+ where
+ isEmptyRow (AnnHeaderRow _attr _rownum cells) = all isEmptyCell cells
+ isEmptyCell (AnnCell _colspecs _colnum cell) =
+ cell == Cell nullAttr AlignDefault (RowSpan 1) (ColSpan 1) []
+
+
+data RowType = HeaderRow | FooterRow | BodyRow
+ deriving (Eq)
+
+data CellType = HeaderCell | BodyCell
+
+data TableRow = TableRow RowType Attr RowNumber AnnRowHead AnnRowBody
+
+headerRowsToHtml :: PandocMonad m
+ => WriterOptions
+ -> [AnnHeaderRow]
+ -> StateT WriterState m Html
+headerRowsToHtml opts =
+ rowListToHtml opts . map toTableRow
+ where
+ toTableRow (AnnHeaderRow attr rownum rowbody) =
+ TableRow HeaderRow attr rownum [] rowbody
+
+bodyRowsToHtml :: PandocMonad m
+ => WriterOptions
+ -> [AnnBodyRow]
+ -> StateT WriterState m Html
+bodyRowsToHtml opts =
+ rowListToHtml opts . zipWith toTableRow [1..]
+ where
+ toTableRow rownum (AnnBodyRow attr _rownum rowhead rowbody) =
+ TableRow BodyRow attr rownum rowhead rowbody
+
+
+rowListToHtml :: PandocMonad m
+ => WriterOptions
+ -> [TableRow]
+ -> StateT WriterState m Html
+rowListToHtml opts rows =
+ (\x -> (nl opts *> mconcat x)) <$>
+ mapM (tableRowToHtml opts) rows
+
+colSpecListToHtml :: PandocMonad m
+ => WriterOptions
+ -> [ColSpec]
+ -> StateT WriterState m Html
+colSpecListToHtml opts colspecs = do
+ html5 <- gets stHtml5
+ let hasDefaultWidth (_, ColWidthDefault) = True
+ hasDefaultWidth _ = False
+
+ let percent w = show (truncate (100*w) :: Integer) <> "%"
+
+ let col :: ColWidth -> Html
+ col cw = do
+ H.col ! case cw of
+ ColWidthDefault -> mempty
+ ColWidth w -> if html5
+ then A.style (toValue $ "width: " <> percent w)
+ else A.width (toValue $ percent w)
+ nl opts
+
+ return $
+ if all hasDefaultWidth colspecs
+ then mempty
+ else do
+ H.colgroup $ do
+ nl opts
+ mapM_ (col . snd) colspecs
+ nl opts
tableRowToHtml :: PandocMonad m
=> WriterOptions
- -> [Alignment]
- -> Int
- -> [[Block]]
+ -> TableRow
-> StateT WriterState m Html
-tableRowToHtml opts aligns rownum cols' = do
- let mkcell = if rownum == 0 then H.th else H.td
- let rowclass = case rownum of
- 0 -> "header"
- x | x `rem` 2 == 1 -> "odd"
- _ -> "even"
- cols'' <- zipWithM
- (\alignment item -> tableItemToHtml opts mkcell alignment item)
- aligns cols'
- return $ (H.tr ! A.class_ rowclass $ nl opts >> mconcat cols'')
- >> nl opts
+tableRowToHtml opts (TableRow rowtype _attr rownum rowhead rowbody) = do
+ let rowclass = A.class_ $ case rownum of
+ RowNumber x | x `rem` 2 == 1 -> "odd"
+ _ | rowtype /= HeaderRow -> "even"
+ _ -> "header"
+ let celltype = case rowtype of
+ HeaderRow -> HeaderCell
+ _ -> BodyCell
+ head' <- mapM (cellToHtml opts HeaderCell) rowhead
+ body <- mapM (cellToHtml opts celltype) rowbody
+ return $ do
+ H.tr ! rowclass $ nl opts *> mconcat (head' <> body)
+ nl opts
-alignmentToString :: Alignment -> [Char]
-alignmentToString alignment = case alignment of
- AlignLeft -> "left"
- AlignRight -> "right"
- AlignCenter -> "center"
- AlignDefault -> ""
+alignmentToString :: Alignment -> Maybe Text
+alignmentToString = \case
+ AlignLeft -> Just "left"
+ AlignRight -> Just "right"
+ AlignCenter -> Just "center"
+ AlignDefault -> Nothing
-tableItemToHtml :: PandocMonad m
+colspanAttrib :: ColSpan -> Attribute
+colspanAttrib = \case
+ ColSpan 1 -> mempty
+ ColSpan n -> A.colspan (toValue n)
+
+rowspanAttrib :: RowSpan -> Attribute
+rowspanAttrib = \case
+ RowSpan 1 -> mempty
+ RowSpan n -> A.rowspan (toValue n)
+
+cellToHtml :: PandocMonad m
+ => WriterOptions
+ -> CellType
+ -> AnnCell
+ -> StateT WriterState m Html
+cellToHtml opts celltype (AnnCell (colspec :| _) _colNum cell) =
+ let align = fst colspec
+ in tableCellToHtml opts celltype align cell
+
+tableCellToHtml :: PandocMonad m
=> WriterOptions
- -> (Html -> Html)
+ -> CellType
-> Alignment
- -> [Block]
+ -> Cell
-> StateT WriterState m Html
-tableItemToHtml opts tag' align' item = do
+tableCellToHtml opts ctype colAlign (Cell attr align rowspan colspan item) = do
contents <- blockListToHtml opts item
html5 <- gets stHtml5
- let alignStr = alignmentToString align'
- let attribs = if html5
- then A.style (toValue $ "text-align: " <> alignStr <> ";")
- else A.align (toValue alignStr)
- let tag'' = if null alignStr
- then tag'
- else tag' ! attribs
- return $ tag'' contents >> nl opts
+ let tag' = case ctype of
+ BodyCell -> H.td
+ HeaderCell -> H.th
+ let align' = case align of
+ AlignDefault -> colAlign
+ _ -> align
+ let alignAttribs = case alignmentToString align' of
+ Nothing ->
+ mempty
+ Just alignStr ->
+ if html5
+ then A.style (toValue $ "text-align: " <> alignStr <> ";")
+ else A.align (toValue alignStr)
+ otherAttribs <- attrsToHtml opts attr
+ let attribs = mconcat
+ $ alignAttribs
+ : colspanAttrib colspan
+ : rowspanAttrib rowspan
+ : otherAttribs
+ return $ do
+ tag' ! attribs $ contents
+ nl opts
toListItems :: WriterOptions -> [Html] -> [Html]
toListItems opts items = map (toListItem opts) items ++ [nl opts]
toListItem :: WriterOptions -> Html -> Html
-toListItem opts item = nl opts >> H.li item
+toListItem opts item = nl opts *> H.li item
blockListToHtml :: PandocMonad m
=> WriterOptions -> [Block] -> StateT WriterState m Html
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
index ce0532ac8..9ae10261e 100644
--- a/test/Tests/Old.hs
+++ b/test/Tests/Old.hs
@@ -67,8 +67,11 @@ tests pandocPath =
]
]
, testGroup "html"
- [ testGroup "writer" (writerTests' "html4" ++ writerTests' "html5" ++
- lhsWriterTests' "html")
+ [ testGroup "writer" $ mconcat
+ [ extWriterTests' "html4"
+ , extWriterTests' "html5"
+ , lhsWriterTests' "html"
+ ]
, test' "reader" ["-r", "html", "-w", "native", "-s"]
"html-reader.html" "html-reader.native"
]
@@ -225,6 +228,7 @@ tests pandocPath =
fb2WriterTest' = fb2WriterTest pandocPath
lhsWriterTests' = lhsWriterTests pandocPath
lhsReaderTest' = lhsReaderTest pandocPath
+ extWriterTests' = extendedWriterTests pandocPath
-- makes sure file is fully closed after reading
readFile' :: FilePath -> IO String
@@ -260,6 +264,19 @@ writerTests pandocPath format
opts = ["-r", "native", "-w", format, "--columns=78",
"--variable", "pandoc-version="]
+extendedWriterTests :: FilePath -> String -> [TestTree]
+extendedWriterTests pandocPath format
+ = writerTests pandocPath format ++
+ [ test pandocPath
+ "tables"
+ opts
+ ("tables" > "planets.native")
+ ("tables" > "planets" <.> format)
+ ]
+ where
+ opts = ["-r", "native", "-w", format, "--columns=78",
+ "--variable", "pandoc-version="]
+
s5WriterTest :: FilePath -> String -> [String] -> String -> TestTree
s5WriterTest pandocPath modifier opts format
= test pandocPath (format ++ " writer (" ++ modifier ++ ")")
diff --git a/test/tables/planets.html4 b/test/tables/planets.html4
new file mode 100644
index 000000000..3e9caa017
--- /dev/null
+++ b/test/tables/planets.html4
@@ -0,0 +1,133 @@
+
+Data about the planets of our solar system.
+
+
+
+
+
+| Terrestial planets |
+Mercury |
+0.330 |
+4,879 |
+5427 |
+3.7 |
+4222.6 |
+57.9 |
+167 |
+0 |
+Closest to the Sun |
+
+
+| Venus |
+4.87 |
+12,104 |
+5243 |
+8.9 |
+2802.0 |
+108.2 |
+464 |
+0 |
+ |
+
+
+| Earth |
+5.97 |
+12,756 |
+5514 |
+9.8 |
+24.0 |
+149.6 |
+15 |
+1 |
+Our world |
+
+
+| Mars |
+0.642 |
+6,792 |
+3933 |
+3.7 |
+24.7 |
+227.9 |
+-65 |
+2 |
+The red planet |
+
+
+| Jovian planets |
+Gas giants |
+Jupiter |
+1898 |
+142,984 |
+1326 |
+23.1 |
+9.9 |
+778.6 |
+-110 |
+67 |
+The largest planet |
+
+
+| Saturn |
+568 |
+120,536 |
+687 |
+9.0 |
+10.7 |
+1433.5 |
+-140 |
+62 |
+ |
+
+
+| Ice giants |
+Uranus |
+86.8 |
+51,118 |
+1271 |
+8.7 |
+17.2 |
+2872.5 |
+-195 |
+27 |
+ |
+
+
+| Neptune |
+102 |
+49,528 |
+1638 |
+11.0 |
+16.1 |
+4495.1 |
+-200 |
+14 |
+ |
+
+
+| Dwarf planets |
+Pluto |
+0.0146 |
+2,370 |
+2095 |
+0.7 |
+153.3 |
+5906.4 |
+-225 |
+5 |
+Declassified as a planet in 2006. |
+
+
+
diff --git a/test/tables/planets.html5 b/test/tables/planets.html5
new file mode 100644
index 000000000..35be2e27f
--- /dev/null
+++ b/test/tables/planets.html5
@@ -0,0 +1,133 @@
+
+Data about the planets of our solar system.
+
+
+
+
+
+| Terrestial planets |
+Mercury |
+0.330 |
+4,879 |
+5427 |
+3.7 |
+4222.6 |
+57.9 |
+167 |
+0 |
+Closest to the Sun |
+
+
+| Venus |
+4.87 |
+12,104 |
+5243 |
+8.9 |
+2802.0 |
+108.2 |
+464 |
+0 |
+ |
+
+
+| Earth |
+5.97 |
+12,756 |
+5514 |
+9.8 |
+24.0 |
+149.6 |
+15 |
+1 |
+Our world |
+
+
+| Mars |
+0.642 |
+6,792 |
+3933 |
+3.7 |
+24.7 |
+227.9 |
+-65 |
+2 |
+The red planet |
+
+
+| Jovian planets |
+Gas giants |
+Jupiter |
+1898 |
+142,984 |
+1326 |
+23.1 |
+9.9 |
+778.6 |
+-110 |
+67 |
+The largest planet |
+
+
+| Saturn |
+568 |
+120,536 |
+687 |
+9.0 |
+10.7 |
+1433.5 |
+-140 |
+62 |
+ |
+
+
+| Ice giants |
+Uranus |
+86.8 |
+51,118 |
+1271 |
+8.7 |
+17.2 |
+2872.5 |
+-195 |
+27 |
+ |
+
+
+| Neptune |
+102 |
+49,528 |
+1638 |
+11.0 |
+16.1 |
+4495.1 |
+-200 |
+14 |
+ |
+
+
+| Dwarf planets |
+Pluto |
+0.0146 |
+2,370 |
+2095 |
+0.7 |
+153.3 |
+5906.4 |
+-225 |
+5 |
+Declassified as a planet in 2006. |
+
+
+
diff --git a/test/tables/planets.native b/test/tables/planets.native
new file mode 100644
index 000000000..4a348ba54
--- /dev/null
+++ b/test/tables/planets.native
@@ -0,0 +1,138 @@
+[Table ("",[],[]) (Caption Nothing
+ [Para [Str "Data about the planets of our solar system."]])
+ [(AlignCenter,ColWidthDefault)
+ ,(AlignCenter,ColWidthDefault)
+ ,(AlignDefault,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignRight,ColWidthDefault)
+ ,(AlignDefault,ColWidthDefault)]
+ (TableHead ("",[],[])
+ [Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2) [Plain [Str ""]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Name"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Mass (10^24kg)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Diameter (km)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Density (kg/m^3)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Gravity (m/s^2)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Length of day (hours)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Distance from Sun (10^6km)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Mean temperature (C)"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Number of moons"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Notes"]]]]
+ )
+ [(TableBody ("",[],[]) (RowHeadColumns 3)
+ []
+ [Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 4) (ColSpan 2) [Plain [Str "Terrestial planets"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Mercury"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0.330"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "4,879"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5427"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "3.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "4222.6"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "57.9"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "167"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Closest to the Sun"]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Venus"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "4.87"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "12,104"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5243"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "8.9"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2802.0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "108.2"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "464"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str ""]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Earth"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5.97"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "12,756"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5514"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "9.8"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "24.0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "149.6"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "15"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Our world"]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Mars"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0.642"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "6,792"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "3933"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "3.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "24.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "227.9"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-65"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "The red planet"]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 4) (ColSpan 1) [Plain [Str "Jovian planets"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1) [Plain [Str "Gas giants"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Jupiter"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1898"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "142,984"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1326"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "23.1"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "9.9"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "778.6"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-110"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "67"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "The largest planet"]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Saturn"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "568"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "120,536"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "687"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "9.0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "10.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1433.5"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-140"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "62"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str ""]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1) [Plain [Str "Ice giants"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Uranus"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "86.8"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "51,118"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1271"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "8.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "17.2"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2872.5"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-195"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "27"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str ""]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Neptune"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "102"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "49,528"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "1638"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "11.0"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "16.1"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "4495.1"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-200"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "14"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str ""]]]
+ ,Row ("",[],[])
+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2) [Plain [Str "Dwarf planets"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Pluto"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0.0146"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2,370"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "2095"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "0.7"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "153.3"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5906.4"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "-225"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "5"]]
+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1) [Plain [Str "Declassified as a planet in 2006."]]]])]
+ (TableFoot ("",[],[])
+ []
+ )
+]