Index: subversion/clients/cmdline/blame-cmd.c
===================================================================
--- subversion/clients/cmdline/blame-cmd.c	(revision 14461)
+++ subversion/clients/cmdline/blame-cmd.c	(working copy)
@@ -24,6 +24,7 @@
 #include "svn_path.h"
 #include "svn_pools.h"
 #include "svn_cmdline.h"
+#include "svn_xml.h"
 #include "svn_time.h"
 #include "cl.h"
 
@@ -37,7 +38,52 @@
 
 
 /*** Code. ***/
+
+/* Prints blame output to standard console in XML mode. */
 static svn_error_t *
+print_blame_xml (svn_stream_t *out,
+                 apr_pool_t *pool,
+                 svn_revnum_t revision,
+                 const char *author,
+                 const char *date)
+{
+  svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+  const char *rev_str = SVN_IS_VALID_REVNUM (revision)
+                        ? apr_psprintf (pool, "%ld", revision)
+                        : "     -";
+
+  /* "<entry ...>" */
+  svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "entry",
+                         "revision", rev_str, NULL);
+
+  /* "<author>xx</author>" */
+  if (author)
+    {
+       svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+                              "author", NULL);
+       svn_xml_escape_cdata_cstring (&sb, author, pool);
+       svn_xml_make_close_tag (&sb, pool, "author");
+    }
+
+  /* "<date>xx</date>" */
+  if (date)
+    {
+       svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+                              "date", NULL);
+       svn_xml_escape_cdata_cstring (&sb, date, pool);
+       svn_xml_make_close_tag (&sb, pool, "date");
+    }
+
+  /* "</entry>" */
+  svn_xml_make_close_tag (&sb, pool, "entry");
+
+  SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
 blame_receiver (void *baton,
                 apr_int64_t line_no,
                 svn_revnum_t revision,
@@ -52,11 +98,11 @@
   apr_time_t atime;
   const char *time_utf8;
   const char *time_stdout;
-  const char *rev_str = SVN_IS_VALID_REVNUM (revision) 
+  const char *rev_str = SVN_IS_VALID_REVNUM (revision)
                         ? apr_psprintf (pool, "%6ld", revision)
                         : "     -";
-  
-  if (opt_state->verbose)
+
+  if (opt_state->verbose || opt_state->xml)
     {
       if (date)
         {
@@ -70,18 +116,52 @@
              abbreviations for the month and weekday names.  Else, the
              line contents will be misaligned. */
           time_stdout = "                                           -";
-      return svn_stream_printf (out, pool, "%s %10s %s %s\n", rev_str, 
-                                author ? author : "         -", 
-                                time_stdout , line);
+
+      if (opt_state->xml)
+        return print_blame_xml (out, pool,
+                                revision,
+                                author ? author : NULL,
+                                date ? date : NULL);
+
+      else
+        return svn_stream_printf (out, pool, "%s %10s %s %s\n", rev_str,
+                                  author ? author : "         -",
+                                  time_stdout , line);
     }
   else
     {
-      return svn_stream_printf (out, pool, "%s %10s %s\n", rev_str, 
-                                author ? author : "         -", line);
+        return svn_stream_printf (out, pool, "%s %10s %s\n", rev_str,
+                                  author ? author : "         -", line);
     }
 }
- 
 
+
+/* Prints XML header in standard console. */
+static svn_error_t *
+print_header_xml (apr_pool_t *pool)
+{
+  svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+  /* <?xml version="1.0" encoding="utf-8"?> */
+  svn_xml_make_header (&sb, pool);
+
+  /* "<blame>" */
+  svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "blame", NULL);
+  return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+/* Prints XML footer in standard console. */
+static svn_error_t *
+print_footer_xml (apr_pool_t *pool)
+{
+  /* "</blame>" */
+  svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+  svn_xml_make_close_tag (&sb, pool, "blame");
+  return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__blame (apr_getopt_t *os,
@@ -128,16 +208,28 @@
   SVN_ERR (svn_stream_for_stdout (&out, pool));
   bl.opt_state = opt_state;
   bl.out = out;
-  
+
   subpool = svn_pool_create (pool);
 
+  /* If output is not incremental, output the XML header and wrap
+     everything in a top-level element. This makes the output in
+     its entirety a well-formed XML document. */
+  if (opt_state->xml && ! opt_state->incremental)
+    SVN_ERR (print_header_xml (pool));
+  else
+    if (opt_state->incremental)
+      return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                               _("'incremental' option only valid in XML "
+                               "mode"));
+
   for (i = 0; i < targets->nelts; i++)
     {
       svn_error_t *err;
       const char *target = ((const char **) (targets->elts))[i];
       const char *truepath;
       svn_opt_revision_t peg_revision;
-      
+      svn_stringbuf_t *sb;
+
       svn_pool_clear (subpool);
       SVN_ERR (svn_cl__check_cancel (ctx->cancel_baton));
       if (is_head_or_base)
@@ -151,7 +243,15 @@
       /* Check for a peg revision. */
       SVN_ERR (svn_opt_parse_path (&peg_revision, &truepath, target,
                                    subpool));
-               
+      /* "<target ...>" */
+      if (opt_state->xml)
+        {
+          sb = svn_stringbuf_create ("", pool);
+          svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "target",
+                                 "path", truepath, NULL);
+          SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+        }
+
       err = svn_client_blame2 (truepath,
                                &peg_revision,
                                &opt_state->start_revision,
@@ -174,8 +274,22 @@
               return err;
             }
         }
+
+      /* "</target>" */
+      if (opt_state->xml)
+        {
+          sb = svn_stringbuf_create ("", pool);
+          svn_xml_make_close_tag (&sb, pool, "target");
+          SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+        }
     }
   svn_pool_destroy (subpool);
 
+  if (opt_state->xml)
+    {
+      if (! opt_state->incremental)
+        SVN_ERR (print_footer_xml (pool));
+    }
+
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c	(revision 14461)
+++ subversion/clients/cmdline/main.c	(working copy)
@@ -192,7 +192,8 @@
        "\n"
        "  If specified, REV determines in which revision the target is first\n"
        "  looked up.\n"),
-    {'r', 'v', SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
+    {'r', 'v', SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt,
+     svn_cl__xml_opt, svn_cl__incremental_opt} },
 
   { "cat", svn_cl__cat, {0},
     N_("Output the content of specified files or URLs.\n"
Index: subversion/clients/cmdline/dtd/blame.dtd
===================================================================
--- subversion/clients/cmdline/dtd/blame.dtd	(revision 0)
+++ subversion/clients/cmdline/dtd/blame.dtd	(revision 0)
@@ -0,0 +1,10 @@
+<!-- XML DTD for Subversion command-line client output. -->
+
+<!-- For "svn blame" -->
+<!ELEMENT blame (target*)>
+<!ELEMENT target (entry*)>
+<!ATTLIST target path CDATA #REQUIRED>  <!-- path or URL: character -->
+<!ELEMENT entry (author?, date?)>
+<!ELEMENT author (#PCDATA)>  <!-- author -->
+<!ELEMENT date (#PCDATA)>  <!-- date and time -->
+<!ATTLIST entry revision CDATA #REQUIRED>  <!-- revision number: integer -->
Index: subversion/tests/clients/cmdline/blame_tests.py
===================================================================
--- subversion/tests/clients/cmdline/blame_tests.py	(revision 14510)
+++ subversion/tests/clients/cmdline/blame_tests.py	(working copy)
@@ -118,8 +118,85 @@
   else:
     raise svntest.Failure ('Failed to find %s in %s' %
       (expected_error, str(errlines)))
-  
 
+
+
+# Return failure, if svn blame doesn't support XML
+#
+def blame_in_xml(sbox):
+  "blame output in XML format"
+
+  output, error = svntest.actions.run_and_verify_svn (None, None, [],
+                                'help', 'blame')
+
+  # Checks for --xml option in blame help
+  output_omsg = "--xml"
+  output_dmsg = ": output in XML"
+
+  for line in output:
+    if line.find (output_omsg) > 0 and \
+      line.find (output_dmsg) > 0:
+        break
+  else:
+    print "'--xml' option not found in: [svn help blame]"
+    raise svntest.Failure
+
+  # Checks for --incremental option in blame help
+  output_omsg = "--incremental"
+  output_dmsg = ": give output suitable for concatenation"
+
+  for line in output:
+    if line.find (output_omsg) > 0 and \
+       line.find (output_dmsg) > 0:
+      break
+  else:
+    print "'--incremental' option not found in: [svn help blame]"
+    raise svntest.Failure
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  file_name = "iota"
+  file_path = os.path.join (wc_dir, file_name)
+  svntest.main.file_append(file_path, "Testing svn blame --xml\n")
+  expected_output = svntest.wc.State(wc_dir, {
+    'iota' : Item(verb='Sending'),
+    })
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        None, None, None, None,
+                                        None, None, wc_dir)
+
+  # Retrieving last changed date from svn info
+  output, error = svntest.actions.run_and_verify_svn (None, None, [],
+                                'log', file_path, '--xml', '-rHEAD')
+  info_msg = "<date>"
+  for line in output:
+    if line.find(info_msg) >= 0:
+       time_str = line[:len(line)]
+  else:
+    svntest.Failure
+
+  template = ["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+              "<blame>\n",
+              "<target\n",
+              "   path=\"%s\">\n" % (file_path),
+              "<entry\n",
+              "   revision=\"2\">\n",
+              "<author>jrandom</author>\n",
+              "%s" % (time_str),
+              "</entry>\n",
+              "</target>\n",
+              "</blame>\n",
+             ]
+
+  output, error = svntest.actions.run_and_verify_svn (None, None, [],
+                                'blame', file_path, '--xml')
+
+  for i in range(0, len(output)):
+    if output[i] != template[i]:
+      raise svntest.Failure
+
+
 ########################################################################
 # Run the tests
 
@@ -129,6 +206,7 @@
               blame_space_in_name,
               blame_binary,
               blame_directory,
+              blame_in_xml,
              ]
 
 if __name__ == '__main__':
