diff options
Diffstat (limited to 'src/utilfuns/utilxml.cpp')
-rw-r--r-- | src/utilfuns/utilxml.cpp | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/src/utilfuns/utilxml.cpp b/src/utilfuns/utilxml.cpp new file mode 100644 index 0000000..9184102 --- /dev/null +++ b/src/utilfuns/utilxml.cpp @@ -0,0 +1,296 @@ +/****************************************************************************** + * utilxml.cpp - implementaion of utility classes to handle XML processing + * + * $Id: utilxml.cpp 2096 2007-10-07 00:40:00Z scribe $ + * + * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org) + * CrossWire Bible Society + * P. O. Box 2528 + * Tempe, AZ 85280-2528 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include <utilxml.h> +#include <ctype.h> +#include <utilstr.h> + +SWORD_NAMESPACE_START + +const char *XMLTag::nullstr = ""; +void XMLTag::parse() const { + int i; + int start; + char *name = 0; + char *value = 0; + attributes.clear(); + + if (!buf) + return; + for (i = 0; ((buf[i]) && (!isalpha(buf[i]))); i++); + for (; buf[i]; i++) { + if (strchr("\t\r\n ", buf[i])) { + // Convert newlines, carriage returns and tabs to spaces + buf[i] = ' '; + + for (; ((buf[i]) && (!isalpha(buf[i]))); i++); + if (buf[i]) { // we have an attribute name + start = i; + // Deprecated: check for following whitespacee + // Should be: for (; (buf[i] && buf[i] != '='; i++); + for (; ((buf[i]) && (!strchr(" =", buf[i]))); i++); + + if (i-start) { + if (name) + delete [] name; + name = new char [ (i-start) + 1 ]; + strncpy(name, buf+start, i-start); + name[i-start] = 0; + } + + // The following does not allow for empty attributes + //for (; ((buf[i]) && (strchr(" =\"\'", buf[i]))); i++); + + // skip space preceding the = sign + // Deprecated: this is not part of the xml spec + for (; buf[i] == ' '; i++) ; + + // skip the = sign + if (buf[i]) + i++; + + // skip space following the = sign + // Deprecated: this is not part of the xml spec + for (; buf[i] == ' '; i++) ; + + // remember and skip the quote sign + char quoteChar = buf[i]; + if (quoteChar) + i++; + + if (buf[i]) { // we have attribute value + start = i; + // Skip until matching quote character + for (; ((buf[i]) && (buf[i] != quoteChar)); i++); + + // Allow for empty quotes + //if (i-start) { + if (value) + delete [] value; + value = new char [ (i-start) + 1 ]; + if (i-start) { + strncpy(value, buf+start, i-start); + } + value[i-start] = 0; + attributes[name] = value; + //} + } + } + } + + // if there are no more characters left then quit + if (!buf[i]) + break; + + } + for (;i;i--) { + if (buf[i] == '/') + empty = true; + if (!strchr(" \t\r\n>\t", buf[i])) + break; + } + + parsed = true; + if (name) delete [] name; + if (value) delete [] value; +} + + +XMLTag::XMLTag(const char *tagString) { + + name = 0; + buf = 0; + setText(tagString); +} + +void XMLTag::setText(const char *tagString) { + parsed = false; + empty = false; + endTag = false; + + if (buf) { + delete [] buf; + buf = 0; + } + + if (!tagString) // assert tagString before proceeding + return; + + stdstr(&buf, tagString); + + int start = 0; + int i; + + // skip beginning silliness + for (i = 0; ((tagString[i]) && (!isalpha(tagString[i]))); i++) { + if (tagString[i] == '/') + endTag = true; + } + start = i; + for (; ((tagString[i]) && (!strchr("\t\r\n />", tagString[i]))); i++); + if (i-start) { + if (name) + delete [] name; + name = new char [ (i-start) + 1 ]; + strncpy(name, tagString+start, i-start); + name[i-start] = 0; + if (tagString[i] == '/') + empty = true; + } +} + +XMLTag::~XMLTag() { + if (buf) + delete [] buf; + if (name) + delete [] name; +} + +const StringList XMLTag::getAttributeNames() const { + StringList retVal; + + if (!parsed) + parse(); + + for (StringPairMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) + retVal.push_back(it->first.c_str()); + + return retVal; +} + + +const char *XMLTag::getPart(const char *buf, int partNum, char partSplit) const { + for (; (buf && partNum); partNum--) { + buf = strchr(buf, partSplit); + if (buf) + buf++; + } + if (buf) { + const char *end = strchr(buf, partSplit); + junkBuf = buf; + if (end) + junkBuf.setSize(end - buf); + return junkBuf.c_str(); + } + return 0; +} + + +int XMLTag::getAttributePartCount(const char *attribName, char partSplit) const { + int count; + const char *buf = getAttribute(attribName); + for (count = 0; buf; count++) { + buf = strchr(buf, partSplit); + if (buf) + buf++; + } + return count; +} + + +const char *XMLTag::getAttribute(const char *attribName, int partNum, char partSplit) const { + + if (!parsed) + parse(); + + StringPairMap::const_iterator it = attributes.find(attribName); + + const char *retVal = 0; + if (it != attributes.end()) + retVal = it->second.c_str(); + + if ((retVal) && (partNum > -1)) + retVal = getPart(retVal, partNum, partSplit); + + return retVal; +} + + +const char *XMLTag::setAttribute(const char *attribName, const char *attribValue, int partNum, char partSplit) { + if (!parsed) + parse(); + + SWBuf newVal = ""; + // set part of an attribute + if (partNum > -1) { + const char *wholeAttr = getAttribute(attribName); + int attrCount = getAttributePartCount(attribName, partSplit); + for (int i = 0; i < attrCount; i++) { + if (i == partNum) { + if (attribValue) { + newVal += attribValue; + newVal += partSplit; + } + else { + // discard this part per null attribValue + } + } + else { + newVal += getPart(wholeAttr, i, partSplit); + newVal += partSplit; + } + } + if (newVal.length()) newVal--; // discard the last partSplit + attribValue = (!attribValue && !newVal.length()) ? 0 : newVal.c_str(); + } + + // perform the actual set + if (attribValue) + attributes[attribName] = attribValue; + else attributes.erase(attribName); + + return attribValue; +} + +const char *XMLTag::toString() const { + SWBuf tag = "<"; + if (!parsed) + parse(); + + if (isEndTag()) + tag.append('/'); + + tag.append(getName()); + for (StringPairMap::iterator it = attributes.begin(); it != attributes.end(); it++) { + //tag.appendFormatted(" %s=\"%s\"", it->first.c_str(), it->second.c_str()); + tag.append(' '); + tag.append(it->first.c_str()); + tag.append((strchr(it->second.c_str(), '\"')) ? "=\'" : "=\""); + tag.append(it->second.c_str()); + tag.append((strchr(it->second.c_str(), '\"'))? '\'' : '\"'); + } + + if (isEmpty()) + tag.append('/'); + + tag.append('>'); + + + if (buf) + delete [] buf; + buf = new char [ tag.length() + 1 ]; + strcpy(buf, tag.c_str()); + + return buf; +} + + +SWORD_NAMESPACE_END |