diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index de9976502b3318623166135906cce0b765271115..d5caa8bd08a0cdcd1ec9d5dce11eb601205dc35a 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -447,9 +447,13 @@ QString Generator::fileBase(const Node *node) const
 
 /*!
   Constructs an href link from an example file name, which
-  is a path to the example file.
+  is a path to the example file. If \a fileExtension is
+  empty (default value), retrieve the file extension from
+  the generator.
  */
-QString Generator::linkForExampleFile(const QString &path, const Node *parent)
+QString Generator::linkForExampleFile(const QString &path,
+                                      const Node *parent,
+                                      const QString &fileExt)
 {
     QString link = path;
     QString modPrefix(parent->physicalModuleName());
@@ -460,10 +464,30 @@ QString Generator::linkForExampleFile(const QString &path, const Node *parent)
     QString res;
     transmogrify(link, res);
     res.append(QLatin1Char('.'));
-    res.append(fileExtension());
+    res.append(fileExt);
+    if (fileExt.isEmpty())
+        res.append(fileExtension());
     return res;
 }
 
+/*!
+    Helper function to construct a title for a file or image page
+    included in an example.
+*/
+QString Generator::exampleFileTitle(const ExampleNode *relative,
+                                    const QString &fileName)
+{
+    QString suffix;
+    if (relative->files().contains(fileName))
+        suffix = QLatin1String(" Example File");
+    else if (relative->images().contains(fileName))
+        suffix = QLatin1String(" Image File");
+    else
+        return suffix;
+
+    return fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1) + suffix;
+}
+
 /*!
   If the \a node has a URL, return the URL as the file name.
   Otherwise, construct the file name from the fileBase() and
@@ -939,62 +963,75 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
             }
         }
     }
+    generateRequiredLinks(node, marker);
+}
+
+/*!
+  Generates either a link to the project folder for example \a node, or a list
+  of links files/images if 'url.examples config' variable is not defined.
+
+  Does nothing for non-example nodes.
+*/
+void Generator::generateRequiredLinks(const Node *node, CodeMarker *marker)
+{
+    if (!node->isExample())
+        return;
+
+    const ExampleNode *en = static_cast<const ExampleNode *>(node);
+    QString exampleUrl = config()->getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES);
 
-    // For examples, generate either a link to the project directory
-    // (if url.examples is defined), or a list of files/images.
-    if (node->isExample()) {
-        const ExampleNode* en = static_cast<const ExampleNode*>(node);
-        QString exampleUrl = config()->getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES);
-        if (!exampleUrl.isEmpty()) {
-            generateLinkToExample(en, marker, exampleUrl);
-        } else if (!en->noAutoList()) {
-            generateFileList(en, marker, false);
-            generateFileList(en, marker, true);
+    if (exampleUrl.isEmpty()) {
+        if (!en->noAutoList()) {
+            generateFileList(en, marker, false); // files
+            generateFileList(en, marker, true);  // images
         }
+    } else {
+        generateLinkToExample(en, marker, exampleUrl);
     }
 }
 
 /*!
-  Generates a link to the project folder for example node \a en.
-  \a baseUrl is the base URL - path information is available in
-  the example node's name() and 'examplesinstallpath' configuration
-  variable.
+  Generates an external link to the project folder for example \a node.
+  The path to the example is appended to \a baseUrl string, or to a
+  specific location within the string marked with the placeholder '\1'
+  character.
 */
 void Generator::generateLinkToExample(const ExampleNode *en,
                                       CodeMarker *marker,
                                       const QString &baseUrl)
 {
-        Text text;
-        QString exampleUrl(baseUrl);
-
-        if (!exampleUrl.contains("\1")) {
-            if (!exampleUrl.endsWith("/"))
-                exampleUrl += "/";
-            exampleUrl += "\1";
-        }
-
-        // Name of the example node is the path, relative to install path
-        QStringList path = QStringList()
-            << config()->getString(CONFIG_EXAMPLESINSTALLPATH)
-            << en->name();
-        path.removeAll({});
-
-        QString link;
+    QString exampleUrl(baseUrl);
+    QString link;
 #ifndef QT_BOOTSTRAPPED
-        link = QUrl(baseUrl).host();
+    link = QUrl(exampleUrl).host();
 #endif
-        if (!link.isEmpty())
-            link.prepend(" @ ");
-        link.prepend("Example project");
+    if (!link.isEmpty())
+        link.prepend(" @ ");
+    link.prepend("Example project");
+
+    const QLatin1Char separator('/');
+    const QLatin1Char placeholder('\1');
+    if (!exampleUrl.contains(placeholder)) {
+        if (!exampleUrl.endsWith(separator))
+            exampleUrl += separator;
+        exampleUrl += placeholder;
+    }
 
-        text << Atom::ParaLeft
-             << Atom(Atom::Link, exampleUrl.replace("\1", path.join("/")))
-             << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
-             << Atom(Atom::String, link)
-             << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
-             << Atom::ParaRight;
+    // Construct a path to the example; <install path>/<example name>
+    QStringList path = QStringList()
+        << config()->getString(CONFIG_EXAMPLESINSTALLPATH)
+        << en->name();
+    path.removeAll({});
+
+    Text text;
+    text << Atom::ParaLeft
+         << Atom(Atom::Link, exampleUrl.replace(placeholder, path.join(separator)))
+         << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+         << Atom(Atom::String, link)
+         << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+         << Atom::ParaRight;
 
-        generateText(text, 0, marker);
+    generateText(text, 0, marker);
 }
 
 /*!
diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h
index d02c59f4409f44d025dd934bb184308a5e9b19c7..61478b2f6c49623046bc434756771d7d7d866fce 100644
--- a/src/qdoc/generator.h
+++ b/src/qdoc/generator.h
@@ -70,9 +70,12 @@ public:
     virtual void terminateGenerator();
 
     QString fullDocumentLocation(const Node *node, bool useSubdir = false);
-    const Config* config() { return config_; }
-    QString linkForExampleFile(const QString &path, const Node *parent);
-
+    const Config *config() { return config_; }
+    QString linkForExampleFile(const QString &path,
+                               const Node *parent,
+                               const QString &fileExt = QString());
+    static QString exampleFileTitle(const ExampleNode *relative,
+                                    const QString &fileName);
     static Generator *currentGenerator() { return currentGenerator_; }
     static Generator *generatorForFormat(const QString& format);
     static void initialize(const Config& config);
@@ -155,11 +158,10 @@ protected:
                                  const Node *relative,
                                  CodeMarker *marker,
                                  bool generate,
-                                 int& numGeneratedAtoms);
-    void generateLinkToExample(const ExampleNode *en,
-                               CodeMarker *marker,
-                               const QString &baseUrl);
-    void generateFileList(const ExampleNode* en, CodeMarker* marker, bool images);
+                                 int &numGeneratedAtoms);
+    void generateRequiredLinks(const Node *node, CodeMarker *marker);
+    void generateLinkToExample(const ExampleNode *en, CodeMarker *marker, const QString &exampleUrl);
+    virtual void generateFileList(const ExampleNode *en, CodeMarker *marker, bool images);
     void generateSince(const Node *node, CodeMarker *marker);
     void generateStatus(const Node *node, CodeMarker *marker);
     void generatePrivateSignalNote(const Node* node, CodeMarker* marker);
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index b9347c108593514c574b063e0a813524965b9005..a9f996a0f1f14f2c9f41415b5b81a84c19618203 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -1271,9 +1271,11 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
             }
         }
     }
-    if (node->isExample()) {
-        const ExampleNode* en = static_cast<const ExampleNode*>(node);
-        foreach (const QString& file, en->files()) {
+    // WebXMLGenerator - skip the nested <page> elements for example
+    // files/images, as the generator produces them separately
+    if (node->isExample() && gen_->format() != QLatin1String("WebXML")) {
+        const ExampleNode *en = static_cast<const ExampleNode *>(node);
+        foreach (const QString &file, en->files()) {
             writer.writeStartElement("page");
             writer.writeAttribute("name", file);
             QString href = gen_->linkForExampleFile(file, en);
@@ -1281,11 +1283,11 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
             writer.writeAttribute("status", "active");
             writer.writeAttribute("subtype", "file");
             writer.writeAttribute("title", "");
-            writer.writeAttribute("fulltitle", file.mid(file.lastIndexOf('/') + 1) + " Example File");
+            writer.writeAttribute("fulltitle", Generator::exampleFileTitle(en, file));
             writer.writeAttribute("subtitle", file);
             writer.writeEndElement(); // page
         }
-        foreach (const QString& file, en->images()) {
+        foreach (const QString &file, en->images()) {
             writer.writeStartElement("page");
             writer.writeAttribute("name", file);
             QString href = gen_->linkForExampleFile(file, en);
@@ -1293,7 +1295,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
             writer.writeAttribute("status", "active");
             writer.writeAttribute("subtype", "image");
             writer.writeAttribute("title", "");
-            writer.writeAttribute("fulltitle", file.mid(file.lastIndexOf('/') + 1) + " Image File");
+            writer.writeAttribute("fulltitle", Generator::exampleFileTitle(en, file));
             writer.writeAttribute("subtitle", file);
             writer.writeEndElement(); // page
         }
diff --git a/src/qdoc/webxmlgenerator.cpp b/src/qdoc/webxmlgenerator.cpp
index 45178c3c17a4cb1623ab584d1095ce6e6d16cb8d..20c65589083b470d3fbca3ebf2e8fb4e88d83a35 100644
--- a/src/qdoc/webxmlgenerator.cpp
+++ b/src/qdoc/webxmlgenerator.cpp
@@ -29,6 +29,7 @@
 #include "webxmlgenerator.h"
 #include "node.h"
 #include "separator.h"
+#include "quoter.h"
 #include "tree.h"
 #include "qdocdatabase.h"
 #include "helpprojectwriter.h"
@@ -64,10 +65,17 @@ QString WebXMLGenerator::fileExtension() const
     return "html";
 }
 
-int WebXMLGenerator::generateAtom(const Atom * /* atom, */,
-                                  const Node * /* relative */,
-                                  CodeMarker * /* marker */)
+/*!
+    Most of the output is generated by QDocIndexFiles and the append() callback.
+    Some pages produce supplementary output while being generated, and that's
+    handled here.
+*/
+int WebXMLGenerator::generateAtom(const Atom *atom,
+                                  const Node *relative,
+                                  CodeMarker *marker)
 {
+    if (supplement && currentWriter)
+        addAtomElements(*currentWriter.data(), atom, relative, marker);
     return 0;
 }
 
@@ -92,23 +100,66 @@ void WebXMLGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker
 }
 
 void WebXMLGenerator::generatePageNode(PageNode *pn, CodeMarker * /* marker */)
+{
+    QByteArray data;
+    currentWriter.reset(new QXmlStreamWriter(&data));
+    currentWriter->setAutoFormatting(true);
+    beginSubPage(pn, Generator::fileName(pn, "webxml"));
+    currentWriter->writeStartDocument();
+    currentWriter->writeStartElement("WebXML");
+    currentWriter->writeStartElement("document");
+
+    generateIndexSections(*currentWriter.data(), pn);
+
+    currentWriter->writeEndElement(); // document
+    currentWriter->writeEndElement(); // WebXML
+    currentWriter->writeEndDocument();
+
+    out() << data;
+    endSubPage();
+}
+
+void WebXMLGenerator::generateExampleFilePage(const Node *en,
+                                            const QString &file,
+                                            CodeMarker * /* marker */)
 {
     QByteArray data;
     QXmlStreamWriter writer(&data);
     writer.setAutoFormatting(true);
-    beginSubPage(pn, Generator::fileName(pn, "webxml"));
+    beginFilePage(en, linkForExampleFile(file, en, "webxml"));
     writer.writeStartDocument();
     writer.writeStartElement("WebXML");
     writer.writeStartElement("document");
+    writer.writeStartElement("page");
+    writer.writeAttribute("name", file);
+    writer.writeAttribute("href", linkForExampleFile(file, en));
+    QString title = exampleFileTitle(static_cast<const ExampleNode *>(en), file);
+    writer.writeAttribute("title", title);
+    writer.writeAttribute("fulltitle", title);
+    writer.writeAttribute("subtitle", file);
+    writer.writeStartElement("description");
+    QString userFriendlyFilePath; // unused
+    writer.writeAttribute("path", Doc::resolveFile(en->doc().location(),
+                                                   file,
+                                                   &userFriendlyFilePath));
+    writer.writeAttribute("line", "0");
+    writer.writeAttribute("column", "0");
+
+    Quoter quoter;
+    Doc::quoteFromFile(en->doc().location(), quoter, file);
+    QString code = quoter.quoteTo(en->location(), QString(), QString());
+    writer.writeTextElement("code", trimmedTrailing(code, QString(), QString()));
 
-    generateIndexSections(writer, pn);
 
+    writer.writeEndElement(); // description
+    writer.writeEndElement(); // page
     writer.writeEndElement(); // document
     writer.writeEndElement(); // WebXML
     writer.writeEndDocument();
 
+
     out() << data;
-    endSubPage();
+    endFilePage();
 }
 
 void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer, Node *node)
@@ -179,6 +230,12 @@ void WebXMLGenerator::append(QXmlStreamWriter &writer, Node *node)
         }
         writer.writeEndElement(); // see-also
     }
+    if (node->isExample()) {
+        supplement = true;
+        generateRequiredLinks(node, marker_);
+        supplement = false;
+    }
+
     writer.writeEndElement(); // description
 }
 
@@ -348,6 +405,26 @@ const Atom *WebXMLGenerator::addAtomElements(QXmlStreamWriter &writer,
         }
         break;
 
+    case Atom::ExampleFileLink:
+    {
+        if (!inLink) {
+            QString link = linkForExampleFile(atom->string(), relative);
+            if (!link.isEmpty())
+                startLink(writer, atom, relative, link);
+        }
+    }
+    break;
+
+    case Atom::ExampleImageLink:
+    {
+        if (!inLink) {
+            QString link = atom->string();
+            if (!link.isEmpty())
+                startLink(writer, atom, nullptr, "images/used-in-examples/" + link);
+        }
+    }
+    break;
+
     case Atom::FootnoteLeft:
         writer.writeStartElement("footnote");
         break;
@@ -452,7 +529,7 @@ const Atom *WebXMLGenerator::addAtomElements(QXmlStreamWriter &writer,
         if (!inLink) {
             const Node *node = nullptr;
             QString link = getLink(atom, relative, &node);
-            if (node)
+            if (!link.isEmpty())
                 startLink(writer, atom, node, link);
         }
         break;
@@ -667,27 +744,41 @@ const Atom *WebXMLGenerator::addAtomElements(QXmlStreamWriter &writer,
 void WebXMLGenerator::startLink(QXmlStreamWriter &writer, const Atom *atom,
                                 const Node *node, const QString &link)
 {
-    QString fullName = node->fullName();
+    QString fullName = link;
+    if (node)
+        fullName = node->fullName();
     if (!fullName.isEmpty() && !link.isEmpty()) {
         writer.writeStartElement("link");
         writer.writeAttribute("raw", atom->string());
         writer.writeAttribute("href", link);
         writer.writeAttribute("type", targetType(node));
-        switch (node->nodeType()) {
-        case Node::Enum:
-            writer.writeAttribute("enum", fullName);
-            break;
-        case Node::Page:
-            writer.writeAttribute("page", fullName);
-            break;
-        case Node::Property:
-        {
-            const PropertyNode *propertyNode = static_cast<const PropertyNode *>(node);
-            if (propertyNode->getters().size() > 0)
-                writer.writeAttribute("getter", propertyNode->getters().at(0)->fullName());
-        }
-        default:
-            ;
+        if (node) {
+            switch (node->nodeType()) {
+            case Node::Enum:
+                writer.writeAttribute("enum", fullName);
+                break;
+            case Node::Example:
+            {
+                const ExampleNode *en = static_cast<const ExampleNode *>(node);
+                QString fileTitle = exampleFileTitle(en, atom->string());
+                if (!fileTitle.isEmpty()) {
+                    writer.writeAttribute("page", fileTitle);
+                    break;
+                }
+            }
+            // fall through
+            case Node::Page:
+                writer.writeAttribute("page", fullName);
+                break;
+            case Node::Property:
+            {
+                const PropertyNode *propertyNode = static_cast<const PropertyNode *>(node);
+                if (propertyNode->getters().size() > 0)
+                    writer.writeAttribute("getter", propertyNode->getters().at(0)->fullName());
+            }
+            default:
+                ;
+            }
         }
         inLink = true;
     }
@@ -695,6 +786,9 @@ void WebXMLGenerator::startLink(QXmlStreamWriter &writer, const Atom *atom,
 
 QString WebXMLGenerator::targetType(const Node *node)
 {
+    if (!node)
+        return "external";
+
     switch (node->nodeType()) {
     case Node::Namespace:
         return "namespace";
@@ -703,6 +797,7 @@ QString WebXMLGenerator::targetType(const Node *node)
     case Node::Union:
         return "class";
     case Node::Page:
+    case Node::Example:
         return "page";
     case Node::Enum:
         return "enum";
diff --git a/src/qdoc/webxmlgenerator.h b/src/qdoc/webxmlgenerator.h
index f243a5402b0d0927adf88f6bb5d0563c490fd871..bdd28dd2f7ba7b717573519bb393648a11c13726 100644
--- a/src/qdoc/webxmlgenerator.h
+++ b/src/qdoc/webxmlgenerator.h
@@ -29,13 +29,14 @@
 #ifndef WEBXMLGENERATOR_H
 #define WEBXMLGENERATOR_H
 
-#include <QtCore/qxmlstream.h>
-
 #include "codemarker.h"
 #include "config.h"
 #include "htmlgenerator.h"
 #include "qdocindexfiles.h"
 
+#include <QtCore/qxmlstream.h>
+#include <QtCore/qscopedpointer.h>
+
 QT_BEGIN_NAMESPACE
 
 class WebXMLGenerator : public HtmlGenerator, public IndexSectionWriter
@@ -55,6 +56,7 @@ protected:
     void generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker) override;
     void generatePageNode(PageNode *pn, CodeMarker *marker) override;
     void generateDocumentation(Node *node) override;
+    void generateExampleFilePage(const Node *en, const QString &file, CodeMarker *marker) override;
     QString fileExtension() const override;
 
     virtual const Atom *addAtomElements(QXmlStreamWriter &writer, const Atom *atom,
@@ -78,6 +80,8 @@ private:
     bool hasQuotingInformation;
     int numTableRows;
     QString quoteCommand;
+    QScopedPointer<QXmlStreamWriter> currentWriter;
+    bool supplement = false;
 };
 
 QT_END_NAMESPACE