diff --git a/xml-conduit/src/Text/XML/Stream/Render.hs b/xml-conduit/src/Text/XML/Stream/Render.hs index a146fe1..75a9308 100644 --- a/xml-conduit/src/Text/XML/Stream/Render.hs +++ b/xml-conduit/src/Text/XML/Stream/Render.hs @@ -19,6 +19,7 @@ module Text.XML.Stream.Render ( orderAttrs, -- * Event rendering + document, tag, content, diff --git a/xml-conduit/src/Text/XML/Stream/Render/Internal.hs b/xml-conduit/src/Text/XML/Stream/Render/Internal.hs index 1fff667..f7eb4d7 100644 --- a/xml-conduit/src/Text/XML/Stream/Render/Internal.hs +++ b/xml-conduit/src/Text/XML/Stream/Render/Internal.hs @@ -21,6 +21,7 @@ module Text.XML.Stream.Render.Internal , rsXMLDeclaration , orderAttrs -- * Event rendering + , document , tag , content -- * Attribute rendering @@ -82,7 +83,11 @@ data RenderSettings = RenderSettings -- -- @since 1.3.3 , rsXMLDeclaration :: Bool - -- ^ Determines whether the XML declaration will be output. + -- ^ Determines whether the XML declaration will be output. Note that when + -- using the streaming API the XML declaration will be output only if this + -- is set to true /and/ the stream includes an 'EventBeginDocument' event. + -- Apart from yielding it explicitly, this can be achieved by wrapping the + -- stream in the 'document' function. -- -- Default: @True@ -- @@ -391,6 +396,14 @@ nubAttrs orig = | k `Set.member` used = (dlist, used) | otherwise = (dlist . ((k, v):), Set.insert k used) +-- | Wrap the given stream in an 'EventBeginDocument'/'EventEndDocument' pair. +-- +-- @since TODO +document :: (Monad m) => ConduitT i Event m () -> ConduitT i Event m () +document content' = do + yield EventBeginDocument + content' + yield EventEndDocument -- | Generate a complete XML 'Element'. tag :: (Monad m) => Name -> Attributes -> ConduitT i Event m () -- ^ 'Element''s subnodes. diff --git a/xml-conduit/test/unit.hs b/xml-conduit/test/unit.hs index a2284e3..8dee4bd 100644 --- a/xml-conduit/test/unit.hs +++ b/xml-conduit/test/unit.hs @@ -25,6 +25,7 @@ import Text.XML.Cursor (($.//), ($/), ($//), ($|), (&.//), (&/), (&//)) import qualified Control.Monad.Trans.Resource as C +import Conduit (foldC, sinkList, yieldMany) import Data.Conduit ((.|), runConduit, runConduitRes, ConduitT) import Data.Conduit.Attoparsec (ParseError(..)) @@ -60,6 +61,8 @@ main = hspec $ do it "normalizes line endings" crlfToLfConversion it "normalizes \\r at the end of a content" crlfToLfConversionCrAtEnd it "normalizes multiple \\rs and \\r\\ns" crlfToLfConversionCrCrCr + context "generates events for rendering in a stream" streamRenderGenerateEvents + it "renders events from a stream" streamRender describe "XML Cursors" $ do it "has correct parent" cursorParent it "has correct ancestor" cursorAncestor @@ -1108,3 +1111,47 @@ crlfToLfConversionCrCrCr = (elementContent $ documentRoot doc) `shouldBe` conten where doc = D.parseLBS_ def "\r\r\r\n\r\r\r" content = [ContentText "\n\n\n\n\n\n"] + +streamRenderGenerateEvents :: Spec +streamRenderGenerateEvents = do + it "generates events for a document" $ do + emptyDoc <- runConduit $ R.document mempty .| sinkList + emptyDoc @?= [EventBeginDocument, EventEndDocument] + nonEmptyDoc <- runConduit $ + R.document (R.tag "foo" mempty $ R.content "...") .| sinkList + nonEmptyDoc @?= + [ EventBeginDocument + , EventBeginElement "foo" [] + , EventContent $ ContentText "..." + , EventEndElement "foo" + , EventEndDocument + ] + it "generates events for a tag" $ do + emptyTag <- runConduit $ R.tag "foo" mempty mempty .| sinkList + emptyTag @?= [EventBeginElement "foo" [], EventEndElement "foo"] + nonEmptyTag <- runConduit $ + R.tag "foo" (R.attr "bar" "baz") (R.content "...") .| sinkList + nonEmptyTag @?= + [ EventBeginElement "foo" [("bar", [ContentText "baz"])] + , EventContent $ ContentText "..." + , EventEndElement "foo" + ] + +streamRender :: Assertion +streamRender = do + x <- runConduit $ input .| R.renderBytes def .| foldC + x @?= output + where + input = yieldMany + [ EventBeginDocument + , EventBeginElement "foo" [("bar", [ContentText "baz"])] + , EventContent $ ContentText "..." + , EventEndElement "foo" + , EventEndDocument + ] + output = S.concat + [ "" + , "" + , "..." + , "" + ]