1
/******************************************************************************
2
* utilxml.cpp - implementaion of utility classes to handle XML processing
4
* $Id: utilxml.cpp 2378 2009-05-04 23:18:51Z scribe $
6
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
7
* CrossWire Bible Society
11
* This program is free software; you can redistribute it and/or modify it
12
* under the terms of the GNU General Public License as published by the
13
* Free Software Foundation version 2.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
28
const char *XMLTag::nullstr = "";
29
void XMLTag::parse() const {
38
for (i = 0; ((buf[i]) && (!isalpha(buf[i]))); i++);
40
if (strchr("\t\r\n ", buf[i])) {
41
// Convert newlines, carriage returns and tabs to spaces
44
for (; ((buf[i]) && (!isalpha(buf[i]))); i++);
45
if (buf[i]) { // we have an attribute name
47
// Deprecated: check for following whitespacee
48
// Should be: for (; (buf[i] && buf[i] != '='; i++);
49
for (; ((buf[i]) && (!strchr(" =", buf[i]))); i++);
54
name = new char [ (i-start) + 1 ];
55
strncpy(name, buf+start, i-start);
59
// The following does not allow for empty attributes
60
//for (; ((buf[i]) && (strchr(" =\"\'", buf[i]))); i++);
62
// skip space preceding the = sign
63
// Deprecated: this is not part of the xml spec
64
for (; buf[i] == ' '; i++) ;
70
// skip space following the = sign
71
// Deprecated: this is not part of the xml spec
72
for (; buf[i] == ' '; i++) ;
74
// remember and skip the quote sign
75
char quoteChar = buf[i];
79
if (buf[i]) { // we have attribute value
81
// Skip until matching quote character
82
for (; ((buf[i]) && (buf[i] != quoteChar)); i++);
84
// Allow for empty quotes
88
value = new char [ (i-start) + 1 ];
90
strncpy(value, buf+start, i-start);
93
attributes[name] = value;
99
// if there are no more characters left then quit
107
if (!strchr(" \t\r\n>\t", buf[i]))
112
if (name) delete [] name;
113
if (value) delete [] value;
117
XMLTag::XMLTag(const char *tagString) {
124
XMLTag::XMLTag(const XMLTag& t) : attributes(t.attributes) {
129
int len = strlen(t.buf);
130
buf = new char[len + 1];
131
memcpy(buf, t.buf, len + 1);
134
int len = strlen(t.name);
135
name = new char[len + 1];
136
memcpy(name, t.name, len + 1);
140
void XMLTag::setText(const char *tagString) {
150
if (!tagString) // assert tagString before proceeding
153
stdstr(&buf, tagString);
158
// skip beginning silliness
159
for (i = 0; ((tagString[i]) && (!isalpha(tagString[i]))); i++) {
160
if (tagString[i] == '/')
164
for (; ((tagString[i]) && (!strchr("\t\r\n />", tagString[i]))); i++);
168
name = new char [ (i-start) + 1 ];
169
strncpy(name, tagString+start, i-start);
171
if (tagString[i] == '/')
183
const StringList XMLTag::getAttributeNames() const {
189
for (StringPairMap::const_iterator it = attributes.begin(); it != attributes.end(); it++)
190
retVal.push_back(it->first.c_str());
196
const char *XMLTag::getPart(const char *buf, int partNum, char partSplit) const {
197
for (; (buf && partNum); partNum--) {
198
buf = strchr(buf, partSplit);
203
const char *end = strchr(buf, partSplit);
206
junkBuf.setSize(end - buf);
207
return junkBuf.c_str();
213
int XMLTag::getAttributePartCount(const char *attribName, char partSplit) const {
215
const char *buf = getAttribute(attribName);
216
for (count = 0; buf; count++) {
217
buf = strchr(buf, partSplit);
225
const char *XMLTag::getAttribute(const char *attribName, int partNum, char partSplit) const {
230
StringPairMap::const_iterator it = attributes.find(attribName);
232
const char *retVal = 0;
233
if (it != attributes.end())
234
retVal = it->second.c_str();
236
if ((retVal) && (partNum > -1))
237
retVal = getPart(retVal, partNum, partSplit);
243
const char *XMLTag::setAttribute(const char *attribName, const char *attribValue, int partNum, char partSplit) {
248
// set part of an attribute
250
const char *wholeAttr = getAttribute(attribName);
251
int attrCount = getAttributePartCount(attribName, partSplit);
252
for (int i = 0; i < attrCount; i++) {
255
newVal += attribValue;
259
// discard this part per null attribValue
263
newVal += getPart(wholeAttr, i, partSplit);
267
if (newVal.length()) newVal--; // discard the last partSplit
268
attribValue = (!attribValue && !newVal.length()) ? 0 : newVal.c_str();
271
// perform the actual set
273
attributes[attribName] = attribValue;
274
else attributes.erase(attribName);
279
const char *XMLTag::toString() const {
287
tag.append(getName());
288
for (StringPairMap::iterator it = attributes.begin(); it != attributes.end(); it++) {
289
//tag.appendFormatted(" %s=\"%s\"", it->first.c_str(), it->second.c_str());
291
tag.append(it->first.c_str());
292
tag.append((strchr(it->second.c_str(), '\"')) ? "=\'" : "=\"");
293
tag.append(it->second.c_str());
294
tag.append((strchr(it->second.c_str(), '\"'))? '\'' : '\"');
305
buf = new char [ tag.length() + 1 ];
306
strcpy(buf, tag.c_str());
312
// if an eID is provided, then we check to be sure we have an attribute <tag eID="xxx"/> value xxx equiv to what is given us
313
// otherwise, we return if we're a simple XML end </tag>.
314
bool XMLTag::isEndTag(const char *eID) const {
316
return (SWBuf(eID) == getAttribute("eID"));