Implementing IXmlWriter Part 5: Supporting WriteAttributeString()
Implementing IXmlWriter c++ ixmlwriter xml
Published: 2005-10-11
Implementing IXmlWriter Part 5: Supporting WriteAttributeString()

This is part 5/14 of my Implementing IXmlWriter post series.

Today I will add support for writing attributes to yesterday’s version of IXmlWriter.

To learn more about attributes, see the W3C XML 1.0 Recommendation. Writing attributes will be supported with the function WriteAttributeString().

Here’s today’s test case:

1
2
3
4
5
6
7
8
9
StringXmlWriter xmlWriter;
xmlWriter.WriteStartElement("root");
  xmlWriter.WriteStartElement("element");
    xmlWriter.WriteAttributeString("att", "value");
  xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();

std::string strXML = xmlWriter.GetXmlString();
// strXML should be <root><element att="value"/></root>

Because the changes in Implementing IXmlWriter Part 4 keep start elements unclosed until another function is called which requires them to be closed (e.g. WriteString() and WriteEndElement()), adding support for writing attributes is very simple. Here’s the version I came up with to pass all test cases:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class StringXmlWriter
{
private:
    std::stack<std::string> m_openedElements;
    std::string m_xmlStr;
    bool m_unclosedStartElement;

public:
    StringXmlWriter() : m_unclosedStartElement(false) {}

    void WriteStartElement(const std::string& localName)
    {
        if (m_unclosedStartElement) {
            m_xmlStr += '>';
            m_unclosedStartElement = false;
        }

        m_openedElements.push(localName);
        m_xmlStr += '<';
        m_xmlStr += localName;
        m_unclosedStartElement = true;
    }

    void WriteEndElement()
    {
        if (m_unclosedStartElement) {
            m_xmlStr += "/>";
            m_unclosedStartElement = false;
        } else {
            std::string lastOpenedElement = m_openedElements.top();
            m_xmlStr += "</";
            m_xmlStr += lastOpenedElement;
            m_xmlStr += '>';
        }
        m_openedElements.pop();
    }

    void WriteString(const std::string& value)
    {
        if (m_unclosedStartElement) {
            m_xmlStr += '>';
            m_unclosedStartElement = false;
        }

        typedef std::string::const_iterator iter_t;
        for (iter_t iter = value.begin(); iter != value.end(); ++iter) {
            if (*iter == '&') {
                m_xmlStr += "&amp;";
            } else if (*iter == '<') {
                m_xmlStr += "&lt;";
            } else if (*iter == '>') {
                m_xmlStr += "&gt;";
            } else {
                m_xmlStr += *iter;
            }
        }
    }

    void WriteElementString(const std::string& localName,
                            const std::string& value)
    {
        WriteStartElement(localName);
        WriteString(value);
        WriteEndElement();
    }

    void WriteAttributeString(const std::string& localName,
                              const std::string& value)
    {
        m_xmlStr += ' ';
        m_xmlStr += localName;
        m_xmlStr += "=\"";
        m_xmlStr += value;
        m_xmlStr += '"';
    }

    std::string GetXmlString() const
    {
        return m_xmlStr;
    }
};