diff --git a/examples/dbusxml.cfg b/examples/dbusxml.cfg
new file mode 100644
index 0000000..e5f6b18
--- /dev/null
+++ b/examples/dbusxml.cfg
@@ -0,0 +1,10 @@
+PROJECT_NAME      = "DBusXMLDocs"
+OUTPUT_DIRECTORY  = dbusxml
+GENERATE_LATEX    = NO
+GENERATE_MAN      = NO
+GENERATE_RTF      = NO
+CASE_SENSE_NAMES  = NO
+INPUT             = dbusxml.xml
+QUIET             = NO
+JAVADOC_AUTOBRIEF = YES
+EXTRACT_ALL       = YES
diff --git a/examples/dbusxml.xml b/examples/dbusxml.xml
new file mode 100644
index 0000000..d1f0c1f
--- /dev/null
+++ b/examples/dbusxml.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" ?>
+<!-- Comment -->
+<!--* File comment -->
+<node name="/SomeNode">
+  <!--* Documentation on the interface -->
+  <interface name="nl.stack.doxygen.test.interface">
+
+    <!--* Document method
+
+          Some extended documentation for the method.
+
+          @param[in] input blah.
+          @param[out] output blub
+     -->
+    <method name="method">
+      <arg direction="in" name="input" type="s"/>
+      <arg direction="out" type="v" name="output"/>
+    </method>
+
+    <signal name="signal">
+      <!--*< Documentation for signal.
+
+             @param parameter some parameter.
+        -->
+      <arg name="parameter" type="s"/>
+    </signal>
+  </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/src/dbusxmlscanner.cpp b/src/dbusxmlscanner.cpp
new file mode 100644
index 0000000..edd1d71
--- /dev/null
+++ b/src/dbusxmlscanner.cpp
@@ -0,0 +1,455 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#include "dbusxmlscanner.h"
+
+#include "commentscan.h"
+#include "entry.h"
+
+#include <qfile.h>
+#include <qxml.h>
+#include <qstring.h>
+
+#include "message.h"
+
+// -----------------------------------------------------------------------
+// DBusXMLHandler class
+// -----------------------------------------------------------------------
+
+class DBusXMLHandler : public QXmlDefaultHandler
+{
+public:
+    DBusXMLHandler(ParserInterface * parser,
+                   QXmlSimpleReader * reader,
+                   const char * file_name,
+                   Entry * root) :
+        m_parser(parser),
+        m_locator(reader),
+        m_globalRoot(root),
+        m_currentInterface(0),
+        m_currentMethod(0),
+        m_currentArgument(0),
+        m_currentEntry(0),
+        m_fileName(file_name)
+    { setDocumentLocator(&m_locator); }
+
+    ~DBusXMLHandler()
+    { }
+
+    bool startElement(const QString &namespaceURI,
+                      const QString &localName,
+                      const QString &qName,
+                      const QXmlAttributes &attributes)
+    {
+        // <debug>
+        msg("startElement: %d: %s, %s, %s.\n", lineNumber(), namespaceURI.ascii(), localName.ascii(), qName.ascii());
+        for(int i = 0; i < attributes.length(); ++i)
+        {
+            msg("   Attributes: %s, %s, %s, %s, %s\n",
+                    attributes.uri(i).ascii(),
+                    attributes.localName(i).ascii(),
+                    attributes.qName(i).ascii(),
+                    attributes.type(i).ascii(),
+                    attributes.value(i).ascii());
+        }
+        // </debug>
+
+        // add to elements stack:
+        m_openElements.prepend(qName);
+
+        // First we need a node.
+        if (isDBusElement(namespaceURI, localName, qName, "node"))
+        {
+            if (!m_currentNode.isEmpty())
+            {
+                // node inside a node: not allowed.
+                return false;
+            }
+            const int idx(indexOf(attributes, "name"));
+            if (idx < 0) { return false; }
+
+            m_currentNode = attributes.value(idx);
+            // A node is actually of little interest, so do nothing here.
+            msg("**** Node name: %s.\n", m_currentNode.ascii());
+            return true;
+        }
+
+        // Then we need an interface.
+        if (isDBusElement(namespaceURI, localName, qName, "interface"))
+        {
+            // We need a nodeName for interfaces:
+            if (m_currentNode.isEmpty())
+            {
+                msg("*********** NO NODE **********\n");
+                return false;
+            }
+
+            if (m_currentInterface)
+            {
+                // interface within an interface: not allowed.
+                msg("*********** Interface inside another interface **********\n");
+                return false;
+            }
+            const int idx(indexOf(attributes, "name"));
+            if (idx < 0) { return false; }
+
+            // A interface is roughly equivalent to a class:
+            m_currentInterface = createEntry();
+
+            m_currentInterface->section = Entry::CLASS_SEC;
+            m_currentInterface->spec = Entry::DBusInterface;
+            m_currentInterface->type = "Interface";
+            m_currentInterface->name = attributes.value(idx);
+
+            msg("**** Interface name: %s.\n", m_currentInterface->name.data());
+
+            return true;
+        }
+
+        if (isDBusElement(namespaceURI, localName, qName, "method") ||
+            isDBusElement(namespaceURI, localName, qName, "signal"))
+        {
+            // We need a interfaceName for methods and signals:
+            if (!m_currentInterface)
+            {
+                msg("*********** NO INTERFACE **********\n");
+                return false;
+            }
+
+            if (m_currentMethod)
+            {
+                // method within a method: not allowed.
+                msg("*********** Method/signal inside another method/signal **********\n");
+                return false;
+            }
+            const int idx(indexOf(attributes, "name"));
+            if (idx < 0) { return false; }
+
+            m_currentMethod = createEntry();
+
+            m_currentMethod->section = Entry::FUNCTION_SEC;
+            m_currentMethod->spec = Entry::DBus;
+            m_currentMethod->name = attributes.value(idx);
+            m_currentMethod->mtype = Method;
+            m_currentMethod->type = "void";
+
+            if (isDBusElement(namespaceURI, localName, qName, "signal"))
+            { m_currentMethod->mtype = Signal; }
+        }
+
+        if (isDBusElement(namespaceURI, localName, qName, "arg"))
+        {
+            // We need a method for arguments:
+            if (!m_currentMethod)
+            {
+                msg("*********** NO METHOD **********\n");
+                return false;
+            }
+
+            if (m_currentArgument)
+            {
+                // method within a method: not allowed.
+                msg("*********** Argument inside another argument **********\n");
+                return false;
+            }
+            const int name_idx(indexOf(attributes, "name"));
+            if (name_idx < 0) { return false; }
+
+            const int type_idx(indexOf(attributes, "type"));
+            if (type_idx < 0) { return false; }
+
+            const int direction_idx(indexOf(attributes, "direction"));
+
+            if (m_currentMethod->mtype == Signal &&
+                direction_idx >= 0 &&
+                attributes.value(direction_idx) != "in")
+            {
+                msg("********** Invalid direction for argument to signal **********\n");
+                return false;
+            }
+
+            m_currentArgument = new Argument;
+            m_currentArgument->type = attributes.value(type_idx);
+            m_currentArgument->name = attributes.value(name_idx);
+            if (direction_idx >= 0)
+            { m_currentArgument->attrib = attributes.value(direction_idx); }
+            else
+            {
+                if (m_currentMethod->mtype == Signal)
+                { m_currentArgument->attrib = "in"; }
+                else
+                { m_currentArgument->attrib = "out"; }
+            }
+        }
+
+        return true;
+    }
+
+    bool endElement(const QString &namespaceURI,
+                    const QString &localName,
+                    const QString &qName)
+    {
+        // <debug>
+        msg("endElement: %d: %s, %s, %s.\n", lineNumber(), namespaceURI.ascii(), localName.ascii(), qName.ascii());
+        // </debug>
+
+        // Clean up elements stack:
+        // Since we made sure to get the elements in the proper order when
+        // adding we do not need to do so again here.
+        if (m_openElements.isEmpty() || m_openElements.first() != qName)
+        {
+            // Malformed XML:
+            msg("*********** MALFORMED XML **********\n");
+            return false;
+        }
+        m_openElements.remove(m_openElements.begin());
+
+        // Interface:
+        if (isDBusElement(namespaceURI, localName, qName, "interface"))
+        {
+            msg("**** Interface: CLOSED.\n");
+            m_currentInterface->endBodyLine = lineNumber();
+            m_globalRoot->addSubEntry(m_currentInterface);
+
+            m_currentInterface = 0;
+        }
+
+        if (isDBusElement(namespaceURI, localName, qName, "method") ||
+            isDBusElement(namespaceURI, localName, qName, "signal"))
+        {
+            msg("**** Method: CLOSED.\n");
+            m_currentMethod->endBodyLine = lineNumber();
+            m_currentInterface->addSubEntry(m_currentMethod);
+
+            m_currentMethod = 0;
+        }
+
+        if (isDBusElement(namespaceURI, localName, qName, "arg"))
+        {
+            m_currentMethod->argList->append(m_currentArgument);
+            m_currentArgument = 0;
+        }
+
+        return true;
+    }
+
+    bool characters(const QString & chars)
+    {
+        // msg("characters: %s.\n", str.ascii());
+        return true;
+    }
+
+    bool comment(const QString & comment_)
+    {
+        msg("**** Comment: %s.\n", comment_.utf8().data());
+        if (!m_comment.isEmpty())
+        {
+            handleComment();
+        }
+
+        m_commentIsJavaStyle = comment_.startsWith(QChar('*'));
+        m_commentIsQtStyle = comment_.startsWith(QChar('!'));
+
+        if (!m_commentIsJavaStyle && !m_commentIsQtStyle)
+        { return true; }
+
+        m_commentLine = lineNumber();
+
+        if (comment_.at(1) == QChar('<'))
+        {
+            msg("ADDING TO PREVIOUS NODE.");
+            m_comment = comment_.mid(2);
+            handleComment();
+        }
+        else
+        { m_comment = comment_.mid(1); }
+
+        return true;
+    }
+
+    void handleComment()
+    {
+        if (m_comment.isEmpty() ||
+            m_currentEntry == 0) { return; }
+
+        msg("**** adding comment %s to node %s.\n",
+             m_comment.utf8().data(),
+             m_currentEntry->name.data());
+
+        QCString text(m_comment);
+
+        m_currentEntry->docFile = m_fileName;
+        m_currentEntry->docLine = m_commentLine;
+
+        int position(0);
+        bool needs_entry(false);
+        bool brief(false);
+        Protection prot(Public);
+
+        while (parseCommentBlock(m_parser,
+                                 m_currentEntry,
+                                 text, m_fileName.utf8().data(), lineNumber(),
+                                 brief, m_commentIsJavaStyle,
+                                 false,
+                                 prot,
+                                 position,
+                                 needs_entry))
+        {
+            if (needs_entry) { createEntry(); }
+        }
+        if (needs_entry) { createEntry(); }
+
+        m_comment = "";
+    }
+
+    QXmlLocator * locator()
+    { return &m_locator; }
+
+    int lineNumber()
+    { return m_locator.lineNumber(); }
+
+    void setSection()
+    {
+        Entry * current = createEntry();
+        current->reset();
+
+        current->name    = m_fileName.utf8();
+        current->section = Entry::SOURCE_SEC;
+        m_globalRoot->addSubEntry(current);
+    }
+
+private:
+    bool isDBusElement(const QString & namespaceURI,
+                       const QString & localName,
+                       const QString & qName,
+                       const QString & element)
+    {
+        return (namespaceURI.isEmpty() && localName == element && qName == element) ||
+               (namespaceURI.isEmpty() && localName.isEmpty() && qName == element);
+    }
+
+    int indexOf(const QXmlAttributes & attributes, const QString & name,
+                 const QString & type = "CDATA", const bool mandatory = true)
+    {
+        const int idx(attributes.index(name));
+        if (idx < 0 || idx > attributes.length()) { return -1; }
+        if (attributes.type(idx) != type) { return -1; }
+        if (mandatory && attributes.value(idx).isEmpty()) { return -1; }
+
+        return idx;
+    }
+
+    Entry * createEntry()
+    {
+        Entry * entry = new Entry();
+
+        entry->protection = Public ;
+        entry->virt       = Normal;
+        entry->stat       = false;
+        entry->objc       = false;
+
+        entry->fileName  = m_fileName;
+        entry->startLine = lineNumber();
+        entry->bodyLine = lineNumber();
+
+        entry->callGraph = false;
+        entry->callerGraph = false;
+
+        initGroupInfo(entry);
+
+        m_currentEntry = entry;
+
+        handleComment();
+
+        return entry;
+    }
+
+    ParserInterface * m_parser;
+    QXmlLocator m_locator;
+    QString m_currentNode;
+    QStringList m_openElements;
+
+    Entry * m_globalRoot;
+    Entry * m_currentInterface;
+    Entry * m_currentMethod;
+    Argument * m_currentArgument;
+    Entry * m_currentEntry;
+
+    QString m_fileName;
+
+    QString m_comment;
+    bool m_commentIsJavaStyle;
+    bool m_commentIsQtStyle;
+    int m_commentLine;
+};
+
+// -----------------------------------------------------------------------
+// DBusXMLScanner
+// -----------------------------------------------------------------------
+
+DBusXMLScanner::DBusXMLScanner()
+{ }
+
+DBusXMLScanner::~DBusXMLScanner()
+{ }
+
+void DBusXMLScanner::parseInput(const char *fileName,
+                                const char *fileBuf,
+                                Entry *root)
+{
+    QFile inputFile(fileName);
+
+    QXmlInputSource inputSource(inputFile);
+    QXmlSimpleReader reader;
+
+    DBusXMLHandler handler(this, &reader, fileName, root);
+    reader.setContentHandler(&handler);
+    reader.setErrorHandler(&handler);
+    reader.setLexicalHandler(&handler);
+
+    groupEnterFile(fileName, 1);
+    handler.setSection();
+    reader.parse(inputSource);
+    groupLeaveFile(fileName, 1);
+}
+
+bool DBusXMLScanner::needsPreprocessing(const QCString &extension)
+{ return (false); }
+
+void DBusXMLScanner::parseCode(CodeOutputInterface &codeOutIntf,
+                               const char *scopeName,
+                               const QCString &input,
+                               bool isExampleBlock,
+                               const char *exampleName,
+                               FileDef *fileDef,
+                               int startLine,
+                               int endLine,
+                               bool inlineFragment,
+                               MemberDef *memberDef)
+{
+    msg("DBusXMLScanner::parseInput: parsing...\n");
+}
+
+void DBusXMLScanner::resetCodeParserState()
+{
+    msg("DBusXMLScanner::resetCodeParserState: Resetting...\n");
+}
+
+void DBusXMLScanner::parsePrototype(const char *text)
+{
+    msg("DBusXMLScanner::parsePrototype: parsing...\n");
+}
diff --git a/src/dbusxmlscanner.h b/src/dbusxmlscanner.h
new file mode 100644
index 0000000..3a4994e
--- /dev/null
+++ b/src/dbusxmlscanner.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef SCANNER_DBUSXML_H
+#define SCANNER_DBUSXML_H
+
+#include "parserintf.h"
+
+/** \brief D-Bus XML parser.
+ *
+ *  This is the D-Bus XML parser for doxygen.
+ */
+class DBusXMLScanner : public ParserInterface
+{
+public:
+    DBusXMLScanner();
+    virtual ~DBusXMLScanner();
+    void parseInput(const char *fileName,
+                    const char *fileBuf,
+                    Entry *root);
+
+    bool needsPreprocessing(const QCString &extension);
+
+    void parseCode(CodeOutputInterface &codeOutIntf,
+                   const char *scopeName,
+                   const QCString &input,
+                   bool isExampleBlock,
+                   const char *exampleName=0,
+                   FileDef *fileDef=0,
+                   int startLine=-1,
+                   int endLine=-1,
+                   bool inlineFragment=FALSE,
+                   MemberDef *memberDef=0
+                  );
+
+    void resetCodeParserState();
+
+    void parsePrototype(const char *text);
+
+private:
+};
+
+#endif
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 51bd291..44e010a 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -71,6 +71,7 @@
 #include "htags.h"
 #include "pyscanner.h"
 #include "fortranscanner.h"
+#include "dbusxmlscanner.h"
 #include "code.h"
 #include "objcache.h"
 #include "store.h"
@@ -9105,6 +9106,7 @@ void initDoxygen()
   Doxygen::parserManager->registerParser("python",  new PythonLanguageScanner);
   Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
   Doxygen::parserManager->registerParser("vhdl",    new VHDLLanguageScanner);
+  Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
 
   // register any additional parsers here...
 
diff --git a/src/entry.h b/src/entry.h
index bf3ed40..2de442b 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -259,7 +259,8 @@ class Entry
       NonAtomic = 0x040000,
       Copy      = 0x080000,
       Retain    = 0x100000,
-      Assign    = 0x200000
+      Assign    = 0x200000,
+      DBus      = 0x400000
     };
     enum ClassSpecifier
     {
@@ -274,7 +275,8 @@ class Entry
       Protocol       = 0x0100,
       Category       = 0x0200,
       SealedClass    = 0x0400,
-      AbstractClass  = 0x0800
+      AbstractClass  = 0x0800,
+      DBusInterface  = 0x1000
     };
     enum GroupDocType
     {
diff --git a/src/libdoxygen.pro.in b/src/libdoxygen.pro.in
index 2eabf69..ec2e93c 100644
--- a/src/libdoxygen.pro.in
+++ b/src/libdoxygen.pro.in
@@ -88,6 +88,7 @@ HEADERS      =	bufstr.h \
                 pyscanner.h \
                 fortrancode.h \
                 fortranscanner.h \
+                dbusxmlscanner.h \
 		qhp.h \
 		qhpxmlwriter.h \
 		qtbc.h \
@@ -229,6 +230,7 @@ SOURCES      =	ce_lex.cpp \
 		vhdlscanner.cpp \
 		xmldocvisitor.cpp \
                 xmlgen.cpp \
+                dbusxmlscanner.cpp \
 
 win32:TMAKE_CXXFLAGS       += -DQT_NODLL 
 win32-msvc:TMAKE_CXXFLAGS  += -Zm200
diff --git a/src/util.cpp b/src/util.cpp
index 5072721..ef6131b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -305,7 +305,8 @@ int guessSection(const char *name)
       n.right(4)==".ixx"  ||
       n.right(4)==".ipp"  ||
       n.right(4)==".i++"  ||
-      n.right(4)==".inl"
+      n.right(4)==".inl"  ||
+      n.right(4)==".xml"
      ) return Entry::SOURCE_SEC;
   if (n.right(2)==".h"   || // header
       n.right(3)==".hh"  ||
@@ -6443,6 +6444,7 @@ g_lang2extMap[] =
   { "python",      "python",  SrcLangExt_Python },
   { "fortran",     "fortran", SrcLangExt_F90    },
   { "vhdl",        "vhdl",    SrcLangExt_VHDL   },
+  { "dbusxml",     "dbusxml", SrcLangExt_XML    },
   { 0,             0,        (SrcLangExt)0      }
 };
 
@@ -6505,6 +6507,7 @@ void initDefaultExtensionMapping()
   updateLanguageMapping(".f90",   "fortran");
   updateLanguageMapping(".vhd",   "vhdl");
   updateLanguageMapping(".vhdl",  "vhdl");
+  updateLanguageMapping(".xml",   "dbusxml");
 }
 
 SrcLangExt getLanguageFromFileName(const QCString fileName)
diff --git a/src/util.h b/src/util.h
index 2b248a3..1c56e90 100644
--- a/src/util.h
+++ b/src/util.h
@@ -95,7 +95,8 @@ enum SrcLangExt
   SrcLangExt_JS     = 0x0400,
   SrcLangExt_Python = 0x0800,
   SrcLangExt_F90    = 0x1000,
-  SrcLangExt_VHDL   = 0x2000
+  SrcLangExt_VHDL   = 0x2000,
+  SrcLangExt_XML    = 0x4000
 };
 
 //--------------------------------------------------------------------
