@@ -32,9 +32,7 @@ module Text.Pandoc.Writers.Docbook (
33import Text.Pandoc.Definition
33import Text.Pandoc.Definition
34import Text.Pandoc.Shared
34import Text.Pandoc.Shared
35−import Text.Pandoc.Writers.HTML ( stringToSmartHtml, stringToHtml )
36import Text.Pandoc.Entities ( encodeEntities )
35import Text.Pandoc.Entities ( encodeEntities )
37−import Text.Html ( stringToHtmlString )
38import Text.Regex ( mkRegex, matchRegex )
36import Text.Regex ( mkRegex, matchRegex )
39import Data.Char ( toLower, ord )
37import Data.Char ( toLower, ord )
40import Data.List ( isPrefixOf, partition )
38import Data.List ( isPrefixOf, partition )
@@ -54,19 +52,21 @@ hierarchicalize :: [Block] -> [Element]
54hierarchicalize [] = []
52hierarchicalize [] = []
55hierarchicalize (block:rest) =
53hierarchicalize (block:rest) =
56 case block of
54 case block of
57− (Header level title) -> let (thisSection, rest') = break (headerAtLeast level) rest in
55+ (Header level title) -> let (thisSection, rest') = break (headerAtLeast
58− (Sec title (hierarchicalize thisSection)):(hierarchicalize rest')
57+ (Sec title (hierarchicalize thisSection)):
58+ (hierarchicalize rest')
59 x -> (Blk x):(hierarchicalize rest)
59 x -> (Blk x):(hierarchicalize rest)
61-- | Convert list of authors to a docbook <author> section
61-- | Convert list of authors to a docbook <author> section
62authorToDocbook :: WriterOptions -> [Char] -> Doc
62authorToDocbook :: WriterOptions -> [Char] -> Doc
63−authorToDocbook options name = indentedInTags "author" $
63+authorToDocbook opts name = inTagsIndented opts "author" $
64 if ',' `elem` name
64 if ',' `elem` name
65 then -- last name first
65 then -- last name first
66 let (lastname, rest) = break (==',') name
66 let (lastname, rest) = break (==',') name
67 firstname = removeLeadingSpace rest in
67 firstname = removeLeadingSpace rest in
68− inTags "firstname" (text $ stringToXML options firstname) <>
68+ inTagsSimple opts "firstname" (text $ stringToSGML opts firstname) <>
69− inTags "surname" (text $ stringToXML options lastname)
69+ inTagsSimple opts "surname" (text $ stringToSGML opts lastname)
70 else -- last name last
70 else -- last name last
71 let namewords = words name
71 let namewords = words name
72 lengthname = length namewords
72 lengthname = length namewords
@@ -74,101 +74,82 @@ authorToDocbook options name = indentedInTags "author" $
74 0 -> ("","")
74 0 -> ("","")
75 1 -> ("", name)
75 1 -> ("", name)
76 n -> (joinWithSep " " (take (n-1) namewords), last namewords) in
76 n -> (joinWithSep " " (take (n-1) namewords), last namewords) in
77− inTags "firstname" (text $ stringToXML options firstname) $$
77+ inTagsSimple opts "firstname" (text $ stringToSGML opts firstname) $$
78− inTags "surname" (text $ stringToXML options lastname)
78+ inTagsSimple opts "surname" (text $ stringToSGML opts lastname)
80-- | Convert Pandoc document to string in Docbook format.
80-- | Convert Pandoc document to string in Docbook format.
81writeDocbook :: WriterOptions -> Pandoc -> String
81writeDocbook :: WriterOptions -> Pandoc -> String
82−writeDocbook options (Pandoc (Meta title authors date) blocks) =
82+writeDocbook opts (Pandoc (Meta title authors date) blocks) =
83− let head = if (writerStandalone options)
83+ let head = if (writerStandalone opts)
84− then text (writerHeader options)
84+ then text (writerHeader opts)
85 else empty
85 else empty
86− meta = if (writerStandalone options)
86+ meta = if (writerStandalone opts)
87− then indentedInTags "articleinfo" $
87+ then inTagsIndented opts "articleinfo" $
88− (inTags "title" (inlinesToDocbook options title)) $$
88+ (inTagsSimple opts "title" (inlinesToDocbook opts title)) $$
89− (vcat (map (authorToDocbook options) authors)) $$
89+ (vcat (map (authorToDocbook opts) authors)) $$
90− (inTags "date" (text date))
90+ (inTagsSimple opts "date" (text $ stringToSGML opts date))
91 else empty
91 else empty
92 blocks' = replaceReferenceLinks blocks
92 blocks' = replaceReferenceLinks blocks
93 (noteBlocks, blocks'') = partition isNoteBlock blocks'
93 (noteBlocks, blocks'') = partition isNoteBlock blocks'
94− options' = options {writerNotes = noteBlocks}
94+ opts' = opts {writerNotes = noteBlocks}
95 elements = hierarchicalize blocks''
95 elements = hierarchicalize blocks''
96− body = text (writerIncludeBefore options') <>
96+ body = text (writerIncludeBefore opts') <>
97− vcat (map (elementToDocbook options') elements) $$
97+ vcat (map (elementToDocbook opts') elements) $$
98− text (writerIncludeAfter options')
98+ text (writerIncludeAfter opts')
99− body' = if writerStandalone options'
99+ body' = if writerStandalone opts'
100− then indentedInTags "article" (meta $$ body)
100+ then inTagsIndented opts "article" (meta $$ body)
101 else body in
101 else body in
102 render $ head $$ body' <> text "\n"
102 render $ head $$ body' <> text "\n"
104−-- | Put the supplied contents between start and end tags of tagType,
105−-- with specified attributes.
106−inTagsWithAttrib :: String -> [(String, String)] -> Doc -> Doc
107−inTagsWithAttrib tagType attribs contents = text ("<" ++ tagType ++
108− (concatMap (\(a, b) -> " " ++ attributeStringToXML a ++
109− "=\"" ++ attributeStringToXML b ++ "\"") attribs)) <>
111− then text " />" -- self-closing tag
112− else text ">" <> contents <> text ("</" ++ tagType ++ ">")
114−-- | Put the supplied contents between start and end tags of tagType.
115−inTags :: String -> Doc -> Doc
116−inTags tagType contents = inTagsWithAttrib tagType [] contents
118−-- | Put the supplied contents in indented block btw start and end tags.
119−indentedInTags :: [Char] -> Doc -> Doc
120−indentedInTags tagType contents = text ("<" ++ tagType ++ ">") $$
121− nest 2 contents $$ text ("</" ++ tagType ++ ">")
123-- | Convert an Element to Docbook.
104-- | Convert an Element to Docbook.
124elementToDocbook :: WriterOptions -> Element -> Doc
105elementToDocbook :: WriterOptions -> Element -> Doc
125−elementToDocbook options (Blk block) = blockToDocbook options block
106+elementToDocbook opts (Blk block) = blockToDocbook opts block
126−elementToDocbook options (Sec title elements) =
107+elementToDocbook opts (Sec title elements) =
127 -- Docbook doesn't allow sections with no content, so insert some if needed
108 -- Docbook doesn't allow sections with no content, so insert some if needed
128 let elements' = if null elements
109 let elements' = if null elements
129 then [Blk (Para [])]
110 then [Blk (Para [])]
130 else elements in
111 else elements in
131− indentedInTags "section" $
112+ inTagsIndented opts "section" $
132− inTags "title" (wrap options title) $$
113+ inTagsSimple opts "title" (wrap opts title) $$
133− vcat (map (elementToDocbook options) elements')
114+ vcat (map (elementToDocbook opts) elements')
135-- | Convert a list of Pandoc blocks to Docbook.
116-- | Convert a list of Pandoc blocks to Docbook.
136blocksToDocbook :: WriterOptions -> [Block] -> Doc
117blocksToDocbook :: WriterOptions -> [Block] -> Doc
137−blocksToDocbook options = vcat . map (blockToDocbook options)
118+blocksToDocbook opts = vcat . map (blockToDocbook opts)
139-- | Convert a list of lists of blocks to a list of Docbook list items.
120-- | Convert a list of lists of blocks to a list of Docbook list items.
140listItemsToDocbook :: WriterOptions -> [[Block]] -> Doc
121listItemsToDocbook :: WriterOptions -> [[Block]] -> Doc
141−listItemsToDocbook options items =
122+listItemsToDocbook opts items =
142− vcat $ map (listItemToDocbook options) items
123+ vcat $ map (listItemToDocbook opts) items
144-- | Convert a list of blocks into a Docbook list item.
125-- | Convert a list of blocks into a Docbook list item.
145listItemToDocbook :: WriterOptions -> [Block] -> Doc
126listItemToDocbook :: WriterOptions -> [Block] -> Doc
146−listItemToDocbook options item =
127+listItemToDocbook opts item =
147 let plainToPara (Plain x) = Para x
128 let plainToPara (Plain x) = Para x
148 plainToPara y = y in
129 plainToPara y = y in
149 let item' = map plainToPara item in
130 let item' = map plainToPara item in
150− indentedInTags "listitem" (blocksToDocbook options item')
131+ inTagsIndented opts "listitem" (blocksToDocbook opts item')
152-- | Convert a Pandoc block element to Docbook.
133-- | Convert a Pandoc block element to Docbook.
153blockToDocbook :: WriterOptions -> Block -> Doc
134blockToDocbook :: WriterOptions -> Block -> Doc
154−blockToDocbook options Blank = text ""
135+blockToDocbook opts Blank = text ""
155−blockToDocbook options Null = empty
136+blockToDocbook opts Null = empty
156−blockToDocbook options (Plain lst) = wrap options lst
137+blockToDocbook opts (Plain lst) = wrap opts lst
157−blockToDocbook options (Para lst) =
138+blockToDocbook opts (Para lst) =
158− indentedInTags "para" (wrap options lst)
139+ inTagsIndented opts "para" (wrap opts lst)
159−blockToDocbook options (BlockQuote blocks) =
140+blockToDocbook opts (BlockQuote blocks) =
160− indentedInTags "blockquote" (blocksToDocbook options blocks)
141+ inTagsIndented opts "blockquote" (blocksToDocbook opts blocks)
161−blockToDocbook options (CodeBlock str) =
142+blockToDocbook opts (CodeBlock str) =
162− text "<screen>\n" <> text (codeStringToXML str) <> text "\n</screen>"
143+ text "<screen>\n" <> text (escapeSGML str) <> text "\n</screen>"
163−blockToDocbook options (BulletList lst) =
144+blockToDocbook opts (BulletList lst) =
164− indentedInTags "itemizedlist" $ listItemsToDocbook options lst
145+ inTagsIndented opts "itemizedlist" $ listItemsToDocbook opts lst
165−blockToDocbook options (OrderedList lst) =
146+blockToDocbook opts (OrderedList lst) =
166− indentedInTags "orderedlist" $ listItemsToDocbook options lst
147+ inTagsIndented opts "orderedlist" $ listItemsToDocbook opts lst
167−blockToDocbook options (RawHtml str) = text str -- raw XML block
148+blockToDocbook opts (RawHtml str) = text str -- raw XML block
168−blockToDocbook options HorizontalRule = empty -- not semantic
149+blockToDocbook opts HorizontalRule = empty -- not semantic
169−blockToDocbook options (Note _ _) = empty -- shouldn't occur
150+blockToDocbook opts (Note _ _) = empty -- shouldn't occur
170−blockToDocbook options (Key _ _) = empty -- shouldn't occur
151+blockToDocbook opts (Key _ _) = empty -- shouldn't occur
171−blockToDocbook options _ = indentedInTags "para" (text "Unknown block type")
152+blockToDocbook opts _ = inTagsIndented opts "para" (text "Unknown block type")
173-- | Put string in CDATA section
154-- | Put string in CDATA section
174cdata :: String -> Doc
155cdata :: String -> Doc
@@ -176,62 +157,47 @@ cdata str = text $ "<![CDATA[" ++ str ++ "]]>"
177-- | Take list of inline elements and return wrapped doc.
158-- | Take list of inline elements and return wrapped doc.
178wrap :: WriterOptions -> [Inline] -> Doc
159wrap :: WriterOptions -> [Inline] -> Doc
179−wrap options lst = fsep $ map (inlinesToDocbook options) (splitBy Space lst)
160+wrap opts lst = fsep $ map (inlinesToDocbook opts) (splitBy Space lst)
181−-- | Escape a string for XML (with "smart" option if specified).
182−stringToXML :: WriterOptions -> String -> String
183−stringToXML options = encodeEntities .
184− (if writerSmart options
185− then stringToSmartHtml
188−-- | Escape string to XML appropriate for attributes
189−attributeStringToXML :: String -> String
190−attributeStringToXML = gsub "\"" """ . codeStringToXML
192−-- | Escape a literal string for XML.
193−codeStringToXML :: String -> String
194−codeStringToXML = encodeEntities . gsub "<" "<" . gsub "&" "&"
196-- | Convert a list of inline elements to Docbook.
162-- | Convert a list of inline elements to Docbook.
197inlinesToDocbook :: WriterOptions -> [Inline] -> Doc
163inlinesToDocbook :: WriterOptions -> [Inline] -> Doc
198−inlinesToDocbook options lst = hcat (map (inlineToDocbook options) lst)
164+inlinesToDocbook opts lst = hcat (map (inlineToDocbook opts) lst)
200-- | Convert an inline element to Docbook.
166-- | Convert an inline element to Docbook.
201inlineToDocbook :: WriterOptions -> Inline -> Doc
167inlineToDocbook :: WriterOptions -> Inline -> Doc
202−inlineToDocbook options (Str str) = text $ stringToXML options str
168+inlineToDocbook opts (Str str) = text $ stringToSGML opts str
203−inlineToDocbook options (Emph lst) =
169+inlineToDocbook opts (Emph lst) =
204− inTags "emphasis" (inlinesToDocbook options lst)
170+ inTagsSimple opts "emphasis" (inlinesToDocbook opts lst)
205−inlineToDocbook options (Strong lst) =
171+inlineToDocbook opts (Strong lst) =
206− inTagsWithAttrib "emphasis" [("role", "strong")]
172+ inTags False opts "emphasis" [("role", "strong")]
207− (inlinesToDocbook options lst)
173+ (inlinesToDocbook opts lst)
208−inlineToDocbook options (Code str) =
174+inlineToDocbook opts (Code str) =
209− inTags "literal" $ text (codeStringToXML str)
175+ inTagsSimple opts "literal" $ text (escapeSGML str)
210−inlineToDocbook options (TeX str) = inlineToDocbook options (Code str)
176+inlineToDocbook opts (TeX str) = inlineToDocbook opts (Code str)
211−inlineToDocbook options (HtmlInline str) = empty
177+inlineToDocbook opts (HtmlInline str) = empty
212−inlineToDocbook options LineBreak =
178+inlineToDocbook opts LineBreak =
213 text $ "<literallayout></literallayout>"
179 text $ "<literallayout></literallayout>"
214−inlineToDocbook options Space = char ' '
180+inlineToDocbook opts Space = char ' '
215−inlineToDocbook options (Link txt (Src src tit)) =
181+inlineToDocbook opts (Link txt (Src src tit)) =
216 case (matchRegex (mkRegex "mailto:(.*)") src) of
182 case (matchRegex (mkRegex "mailto:(.*)") src) of
217− Just [addr] -> inTags "email" $ text (codeStringToXML addr)
183+ Just [addr] -> inTagsSimple opts "email" $ text (escapeSGML addr)
218− Nothing -> inTagsWithAttrib "ulink" [("url", src)] $
184+ Nothing -> inTags False opts "ulink" [("url", src)] $
219− inlinesToDocbook options txt
185+ inlinesToDocbook opts txt
220−inlineToDocbook options (Link text (Ref ref)) = empty -- shouldn't occur
186+inlineToDocbook opts (Link text (Ref ref)) = empty -- shouldn't occur
221−inlineToDocbook options (Image alt (Src src tit)) =
187+inlineToDocbook opts (Image alt (Src src tit)) =
222 let titleDoc = if null tit
188 let titleDoc = if null tit
223 then empty
189 then empty
224− else indentedInTags "objectinfo" $
190+ else inTagsIndented opts "objectinfo" $
225− indentedInTags "title"
191+ inTagsIndented opts "title"
226− (text $ stringToXML options tit) in
192+ (text $ stringToSGML opts tit) in
227− indentedInTags "inlinemediaobject" $
193+ inTagsIndented opts "inlinemediaobject" $
228− indentedInTags "imageobject" $
194+ inTagsIndented opts "imageobject" $
229− titleDoc $$ inTagsWithAttrib "imagedata" [("fileref", src)] empty
195+ titleDoc $$ selfClosingTag opts "imagedata" [("fileref", src)]
230−inlineToDocbook options (Image alternate (Ref ref)) = empty --shouldn't occur
196+inlineToDocbook opts (Image alternate (Ref ref)) = empty --shouldn't occur
231−inlineToDocbook options (NoteRef ref) =
197+inlineToDocbook opts (NoteRef ref) =
232− let notes = writerNotes options
198+ let notes = writerNotes opts
233 hits = filter (\(Note r _) -> r == ref) notes in
199 hits = filter (\(Note r _) -> r == ref) notes in
234 if null hits
200 if null hits
235 then empty
201 then empty
236 else let (Note _ contents) = head hits in
202 else let (Note _ contents) = head hits in
237− indentedInTags "footnote" $ blocksToDocbook options contents
203+ inTagsIndented opts "footnote" $ blocksToDocbook opts contents