-
Notifications
You must be signed in to change notification settings - Fork 83
/
xml2_utils.h
188 lines (146 loc) · 4.77 KB
/
xml2_utils.h
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#ifndef __XML2_XML_UTILS__
#define __XML2_XML_UTILS__
#define R_NO_REMAP
#include <Rinternals.h>
#undef R_NO_REMAP
#include <libxml/tree.h>
#include <map>
#include <string>
enum NodeType {
missing = 1,
node = 2,
nodeset = 3,
};
inline int inherits3(SEXP x, const char *name) {
SEXP expr = PROTECT(Rf_lang3(Rf_install("inherits"), x, Rf_mkString(name)));
SEXP result = PROTECT(Rf_eval(expr, R_GlobalEnv));
int out = LOGICAL(result)[0];
UNPROTECT(2);
return out;
}
inline const NodeType getNodeType(SEXP x) {
// for fhircrackr
if (IS_S4_OBJECT(x)) {
if (inherits3(x, "xml_node")) {
return(NodeType::node);
} else if (inherits3(x, "xml_nodeset")) {
return(NodeType::nodeset);
} else if (inherits3(x, "xml_missing")) {
return(NodeType::missing);
} else {
Rf_error("Unexpected node type");
}
}
if (Rf_inherits(x, "xml_node")) {
return(NodeType::node);
} else if (Rf_inherits(x, "xml_nodeset")) {
return(NodeType::nodeset);
} else if (Rf_inherits(x, "xml_missing")) {
return(NodeType::missing);
} else {
Rf_error("Unexpected node type");
}
}
inline const xmlChar* asXmlChar(std::string const& x) {
return (const xmlChar*) x.c_str();
}
inline const xmlChar* asXmlChar(SEXP x, int n = 0) {
return (const xmlChar*) CHAR(STRING_ELT(x, n));
}
#define BEGIN_CPP try {
#define END_CPP \
} \
catch (std::exception & e) { \
Rf_error("C++ exception: %s", e.what()); \
}
// If we are using C++11 disallow moves
#if __cplusplus >= 201103L
void asXmlChar(std::string&&) = delete;
#endif
// ----------------------------------------------------------------------------
// A wrapper around xmlChar* that frees memory if necessary
class Xml2String {
xmlChar* string_;
bool free_;
public:
Xml2String(): string_(NULL), free_(false) {}
Xml2String(xmlChar* string): string_(string), free_(true) {}
// Pointers into structs are const, so don't need to be freed
Xml2String(const xmlChar* string): string_((xmlChar*) string), free_(false) {}
// Some strings are regular strings
Xml2String(const char* string): string_((xmlChar*) string), free_(false) {}
~Xml2String() {
try {
if (free_ && string_ != NULL)
xmlFree(string_);
} catch (...) {}
}
std::string asStdString(std::string missing = "") {
if (string_ == NULL)
return missing;
return std::string((char*) string_);
}
SEXP asRString(SEXP missing = NA_STRING) {
if (string_ == NULL)
return missing;
return Rf_mkCharCE((char*) string_, CE_UTF8);
};
};
// ----------------------------------------------------------------------------
// A wrapper around a pair of character vectors used to namespaces to prefixes
class NsMap {
// We only store the index to avoid duplicating the data
typedef std::multimap<std::string, std::string> prefix2url_t;
prefix2url_t prefix2url;
public:
NsMap() {
}
// Initialise from an existing STRSXP
NsMap(SEXP x) {
SEXP names = Rf_getAttrib(x, R_NamesSymbol);
for (R_len_t i = 0; i < Rf_xlength(x); ++i) {
add(std::string(CHAR(STRING_ELT(names, i))), std::string(CHAR(STRING_ELT(x, i))));
}
}
bool hasPrefix(const std::string& prefix) {
return prefix2url.find(prefix) != prefix2url.end();
}
std::string findUrl(const std::string& prefix) {
prefix2url_t::const_iterator it = prefix2url.find(prefix);
if (it != prefix2url.end()) {
return it->second;
}
Rf_error("Couldn't find url for prefix %s", prefix.c_str());
return std::string();
}
std::string findPrefix(const std::string& url) {
for (prefix2url_t::const_iterator it = prefix2url.begin(); it != prefix2url.end(); ++it) {
if (it->second == url) {
return it->first;
}
}
Rf_error("Couldn't find prefix for url %s", url.c_str());
return std::string();
}
bool add(const xmlChar* prefix, const xmlChar* url) {
return add(Xml2String(prefix).asStdString(), Xml2String(url).asStdString());
}
bool add(std::string prefix, std::string url) {
prefix2url.insert(prefix2url_t::value_type(prefix, url));
return true;
}
SEXP out() {
SEXP out = PROTECT(Rf_allocVector(STRSXP, prefix2url.size()));
SEXP names = PROTECT(Rf_allocVector(STRSXP, prefix2url.size()));
size_t i = 0;
for (prefix2url_t::const_iterator it = prefix2url.begin(); it != prefix2url.end(); ++it) {
SET_STRING_ELT(out, i, Rf_mkChar(it->second.c_str()));
SET_STRING_ELT(names, i, Rf_mkChar(it->first.c_str()));
++i;
}
Rf_setAttrib(out, R_NamesSymbol, names);
UNPROTECT(2);
return out;
}
};
#endif