diff --git a/Text/XML.hs b/Text/XML.hs
--- a/Text/XML.hs
+++ b/Text/XML.hs
@@ -59,6 +59,7 @@
     , R.rsPretty
     , R.rsNamespaces
     , R.rsAttrOrder
+    , R.orderAttrs
       -- * Conversion
     , toXMLDocument
     , fromXMLDocument
diff --git a/Text/XML/Stream/Render.hs b/Text/XML/Stream/Render.hs
--- a/Text/XML/Stream/Render.hs
+++ b/Text/XML/Stream/Render.hs
@@ -12,6 +12,7 @@
     , rsPretty
     , rsNamespaces
     , rsAttrOrder
+    , orderAttrs
     , prettify
     ) where
 
@@ -66,6 +67,26 @@
         , rsNamespaces = []
         , rsAttrOrder = const Map.toList
         }
+
+-- | Convenience function to create an ordering function suitable for
+-- use as the value of 'rsAttrOrder'. The ordering function is created
+-- from a list of tuples, as follows: in each tuple, the first
+-- component is the 'Name' of an element, and the second component is
+-- a list of attributes names. When the given element is rendered, the
+-- attributes listed, when present, appears first in the given order,
+-- followed by any other attributes in arbitrary order. If an element
+-- does not appear, all of its attributes are rendered in arbitrary
+-- order.
+orderAttrs :: [(Name, [Name])] ->
+              Name -> Map Name Text -> [(Name, Text)]
+orderAttrs orderSpec = order
+  where
+    order elt attrMap =
+      let initialAttrs = fromMaybe [] $ lookup elt orderSpec
+          mkPair attr = fmap ((,) attr) $ Map.lookup attr attrMap
+          otherAttrMap =
+            Map.filterWithKey (const . not . (`elem` initialAttrs)) attrMap
+      in mapMaybe mkPair initialAttrs ++ Map.toAscList otherAttrMap
 
 -- | Render a stream of 'Event's into a stream of 'Builder's. Builders are from
 -- the blaze-builder package, and allow the create of optimally sized
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -80,6 +80,8 @@
         it "works" caseBlazeHtml
     describe "attribute reordering" $ do
         it "works" caseAttrReorder
+    describe "ordering attributes explicitly" $ do
+        it "works" caseOrderAttrs
 
 documentParseRender :: IO ()
 documentParseRender =
@@ -466,6 +468,26 @@
                         case name of
                             "foo" -> reverse $ Map.toAscList m
                             _ -> Map.toAscList m
+                 }
+        attrs = Map.fromList [("a", "a"), ("b", "b"), ("c", "c")]
+        doc = Res.Document (Res.Prologue [] Nothing [])
+                (Res.Element "foo" attrs
+                    [ Res.NodeElement
+                        $ Res.Element "bar" attrs []
+                    ])
+                []
+    lbs @=? S.concat (L.toChunks $ Res.renderLBS rs doc)
+
+caseOrderAttrs :: Assertion
+caseOrderAttrs = do
+    let lbs = S.concat
+            [ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            , "<foo c=\"c\" b=\"b\" a=\"a\">"
+            , "<bar a=\"a\" b=\"b\" c=\"c\"/>"
+            , "</foo>"
+            ]
+        rs = def { Res.rsAttrOrder = Res.orderAttrs
+                     [("foo", ["c", "b"])]
                  }
         attrs = Map.fromList [("a", "a"), ("b", "b"), ("c", "c")]
         doc = Res.Document (Res.Prologue [] Nothing [])
diff --git a/xml-conduit.cabal b/xml-conduit.cabal
--- a/xml-conduit.cabal
+++ b/xml-conduit.cabal
@@ -1,5 +1,5 @@
 name:            xml-conduit
-version:         1.0.1.1
+version:         1.0.2
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michaels@suite-sol.com>, Aristid Breitkreuz <aristidb@googlemail.com>
