Repository navigation
Expand file tree
/
Copy pathxml_parser.h
More file actions
120 lines (100 loc) · 4.68 KB
/
Copy pathxml_parser.h
File metadata and controls
120 lines (100 loc) · 4.68 KB
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once
/**
* Minimal, allocation-efficient XML parser for OOXML use.
*
* Supports the subset of XML found in .docx files:
* - UTF-8 content
* - Namespaced elements/attributes (prefix:local)
* - Entity references: & < > " '
* - CDATA sections
* - Comments (skipped)
* - Processing instructions (skipped)
*
* Uses a SAX-style callback interface to avoid building a full DOM tree,
* except for a small DOM builder used for comments.xml.
*
* No external dependencies beyond <string>, <vector>, <functional>.
*/
#include <string>
#include <string_view>
#include <vector>
#include <functional>
#include <unordered_map>
#include <memory>
#include <stdexcept>
#include <cstring>
#include <cassert>
namespace docx {
// ─── Attribute ────────────────────────────────────────────────────────────────
struct XmlAttr {
std::string prefix; // may be empty
std::string local; // local name
std::string value;
std::string qname() const { return prefix.empty() ? local : prefix + ":" + local; }
};
using XmlAttrs = std::vector<XmlAttr>;
// ─── SAX callbacks ───────────────────────────────────────────────────────────
struct SaxHandler {
// prefix:local (prefix may be empty)
std::function<void(std::string_view prefix, std::string_view local,
const XmlAttrs& attrs)> start_element;
std::function<void(std::string_view prefix, std::string_view local)> end_element;
std::function<void(std::string_view text)> characters;
};
// ─── SAX parser ──────────────────────────────────────────────────────────────
/**
* Stream a null-terminated (or length-bounded) XML buffer through SAX callbacks.
* Returns false on unrecoverable parse error.
*/
bool sax_parse(const char* data, std::size_t len, SaxHandler& handler);
// ─── Minimal DOM ─────────────────────────────────────────────────────────────
struct XmlNode {
std::string prefix;
std::string local;
XmlAttrs attrs;
std::string text; // concatenated character data
std::vector<std::unique_ptr<XmlNode>> children;
bool is(const char* lname) const { return local == lname; }
/** Get attribute value by local name (ignoring prefix). */
std::string attr(const char* lname) const {
for (const auto& a : attrs)
if (a.local == lname) return a.value;
return {};
}
/** First child with given local name. */
XmlNode* child(const char* lname) const {
for (const auto& c : children)
if (c->local == lname) return c.get();
return nullptr;
}
};
/**
* Parse XML into a DOM tree. Returns nullptr on error.
*/
std::unique_ptr<XmlNode> dom_parse(const char* data, std::size_t len);
// ─── Helpers ─────────────────────────────────────────────────────────────────
/** Collect all text below a node (recursive). */
std::string node_text(const XmlNode& node);
/** Truncate a string to max_bytes (at a UTF-8 boundary). */
std::string truncate_utf8(const std::string& s, std::size_t max_bytes);
/**
* Convert an arbitrary-encoded XML byte stream to UTF-8.
*
* Detects encoding via BOM (UTF-8/16/32 LE/BE) and/or the XML declaration's
* encoding="..." attribute. Supported encodings include:
* - Unicode: UTF-8, UTF-16 LE/BE, UTF-32 LE/BE (with or without BOM)
* - European: ISO-8859-1..16, Windows-125x, KOI8-R/U, IBM OEM codepages
* - Asian: Shift-JIS, GBK/GB2312, GB18030, Big5, EUC-JP/KR/CN,
* ISO-2022-JP/KR/CN
* - Other: TIS-620 (Thai), US-ASCII, and any encoding supported by the
* platform's iconv (Linux/macOS) or MultiByteToWideChar (Windows).
*
* Returns the UTF-8 string. If the input is already valid UTF-8 (the common
* case for OOXML), a copy is returned without any conversion overhead beyond
* a BOM strip if needed.
*
* A trailing NUL byte appended by callers for parser safety is silently
* stripped before conversion.
*/
std::string transcode_to_utf8(const char* data, std::size_t len);
} // namespace docx