git.iko.soy/typeable/pandoc
on master help sign in
HTML reader: Support base tag.

We only support the href attribute, as there's no place for "target" in the Pandoc document model for links. Added HTML reader test module, with tests for this feature. Closes #1751.

commite06810499e69b23f08fc1f8fb7e774e7b11be713 authorJohn MacFarlane <jgm@berkeley.edu> dateWed 13 May 2015, 20:39 (11 years ago) parent75cfa7b
4 files changed+58−7
pandoc.cabal+1 src/Text/Pandoc/Readers/HTML.hs+28−7 tests/Tests/Readers/HTML.hs+27 tests/test-pandoc.hs+2
pandoc.cabal+1
@@ -481,6 +481,7 @@ Test-Suite test-pandoc
481481 Tests.Shared
482482 Tests.Walk
483483 Tests.Readers.LaTeX
484+ Tests.Readers.HTML
484485 Tests.Readers.Markdown
485486 Tests.Readers.Org
486487 Tests.Readers.RST
src/Text/Pandoc/Readers/HTML.hs+28−7
@@ -62,7 +62,7 @@ import Debug.Trace (trace)
6262import Text.TeXMath (readMathML, writeTeX)
6363import Data.Default (Default (..), def)
6464import Control.Monad.Reader (Reader,ask, asks, local, runReader)
65−
65+import Network.URI (isURI)
6666import Text.Pandoc.Error
6767
6868import Text.Parsec.Error
@@ -74,7 +74,8 @@ readHtml :: ReaderOptions -- ^ Reader options
7474 -> Either PandocError Pandoc
7575readHtml opts inp =
7676 mapLeft (ParseFailure . getError) . flip runReader def $
77− runParserT parseDoc (HTMLState def{ stateOptions = opts } []) "source" tags
77+ runParserT parseDoc (HTMLState def{ stateOptions = opts } [] Nothing)
78+ "source" tags
7879 where tags = stripPrefixes . canonicalizeTags $
7980 parseTagsOptions parseOptions{ optTagPosition = True } inp
8081 parseDoc = do
@@ -98,7 +99,8 @@ replaceNotes' x = return x
9899data HTMLState =
99100 HTMLState
100101 { parserState :: ParserState,
101− noteTable :: [(String, Blocks)]
102+ noteTable :: [(String, Blocks)],
103+ baseHref :: Maybe String
102104 }
103105
104106data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext
@@ -120,7 +122,7 @@ pBody :: TagParser Blocks
120122pBody = pInTags "body" block
121123
122124pHead :: TagParser Blocks
123−pHead = pInTags "head" $ pTitle <|> pMetaTag <|> (mempty <$ pAnyTag)
125+pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag)
124126 where pTitle = pInTags "title" inline >>= setTitle . trimInlines
125127 setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
126128 pMetaTag = do
@@ -132,6 +134,17 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> (mempty <$ pAnyTag)
132134 let content = fromAttrib "content" mt
133135 updateState $ B.setMeta name (B.text content)
134136 return mempty
137+ pBaseTag = do
138+ bt <- pSatisfy (~== TagOpen "base" [])
139+ let baseH = fromAttrib "href" bt
140+ if null baseH
141+ then return mempty
142+ else do
143+ let baseH' = case reverse baseH of
144+ '/':_ -> baseH
145+ _ -> baseH ++ "/"
146+ updateState $ \st -> st{ baseHref = Just baseH' }
147+ return mempty
135148
136149block :: TagParser Blocks
137150block = do
@@ -566,7 +579,11 @@ pAnchor = try $ do
566579pRelLink :: TagParser Inlines
567580pRelLink = try $ do
568581 tag <- pSatisfy (tagOpenLit "a" (isJust . lookup "href"))
569− let url = fromAttrib "href" tag
582+ mbBaseHref <- baseHref <$> getState
583+ let url' = fromAttrib "href" tag
584+ let url = case (isURI url', mbBaseHref) of
585+ (False, Just h) -> h ++ url'
586+ _ -> url'
570587 let title = fromAttrib "title" tag
571588 let uid = fromAttrib "id" tag
572589 let spanC = case uid of
@@ -578,7 +595,11 @@ pRelLink = try $ do
578595pImage :: TagParser Inlines
579596pImage = do
580597 tag <- pSelfClosing (=="img") (isJust . lookup "src")
581− let url = fromAttrib "src" tag
598+ mbBaseHref <- baseHref <$> getState
599+ let url' = fromAttrib "src" tag
600+ let url = case (isURI url', mbBaseHref) of
601+ (False, Just h) -> h ++ url'
602+ _ -> url'
582603 let title = fromAttrib "title" tag
583604 let alt = fromAttrib "alt" tag
584605 return $ B.image (escapeURI url) title (B.text alt)
@@ -945,7 +966,7 @@ instance HasReaderOptions HTMLState where
945966 extractReaderOptions = extractReaderOptions . parserState
946967
947968instance Default HTMLState where
948− def = HTMLState def []
969+ def = HTMLState def [] Nothing
949970
950971instance HasMeta HTMLState where
951972 setMeta s b st = st {parserState = setMeta s b $ parserState st}
tests/Tests/Readers/HTML.hsnew file+27
@@ -0,0 +1,27 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.HTML (tests) where
3+
4+import Text.Pandoc.Definition
5+import Test.Framework
6+import Tests.Helpers
7+import Tests.Arbitrary()
8+import Text.Pandoc.Builder
9+import Text.Pandoc
10+import Text.Pandoc.Error
11+
12+html :: String -> Pandoc
13+html = handleError . readHtml def
14+
15+tests :: [Test]
16+tests = [ testGroup "base tag"
17+ [ test html "simple" $
18+ "<head><base href=\"http://www.w3schools.com/images\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
19+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
20+ , test html "slash at end of base" $
21+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
22+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
23+ , test html "absolute URL" $
24+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?>
25+ plain (image "http://example.com/stickman.gif" "" (text "Stickman"))
26+ ]
27+ ]
tests/test-pandoc.hs+2
@@ -8,6 +8,7 @@ import qualified Tests.Old
88import qualified Tests.Readers.LaTeX
99import qualified Tests.Readers.Markdown
1010import qualified Tests.Readers.Org
11+import qualified Tests.Readers.HTML
1112import qualified Tests.Readers.RST
1213import qualified Tests.Readers.Docx
1314import qualified Tests.Readers.Txt2Tags
@@ -46,6 +47,7 @@ tests = [ testGroup "Old" Tests.Old.tests
4647 , testGroup "Readers"
4748 [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
4849 , testGroup "Markdown" Tests.Readers.Markdown.tests
50+ , testGroup "HTML" Tests.Readers.HTML.tests
4951 , testGroup "Org" Tests.Readers.Org.tests
5052 , testGroup "RST" Tests.Readers.RST.tests
5153 , testGroup "Docx" Tests.Readers.Docx.tests