3 * Copyright 2004--2005, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "talk/xmllite/xmlnsstack.h"
34 #include "talk/xmllite/xmlconstants.h"
35 #include "talk/xmllite/xmlelement.h"
39 XmlnsStack::XmlnsStack() :
40 pxmlnsStack_(new std::vector<std::string>),
41 pxmlnsDepthStack_(new std::vector<size_t>) {
44 XmlnsStack::~XmlnsStack() {}
46 void XmlnsStack::PushFrame() {
47 pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
50 void XmlnsStack::PopFrame() {
51 size_t prev_size = pxmlnsDepthStack_->back();
52 pxmlnsDepthStack_->pop_back();
53 if (prev_size < pxmlnsStack_->size()) {
54 pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
59 std::pair<std::string, bool> XmlnsStack::NsForPrefix(
60 const std::string& prefix) {
61 if (prefix.length() >= 3 &&
62 (prefix[0] == 'x' || prefix[0] == 'X') &&
63 (prefix[1] == 'm' || prefix[1] == 'M') &&
64 (prefix[2] == 'l' || prefix[2] == 'L')) {
66 return std::make_pair(NS_XML, true);
67 if (prefix == "xmlns")
68 return std::make_pair(NS_XMLNS, true);
69 // Other names with xml prefix are illegal.
70 return std::make_pair(STR_EMPTY, false);
73 std::vector<std::string>::iterator pos;
74 for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
77 return std::make_pair(*(pos + 1), true);
80 if (prefix == STR_EMPTY)
81 return std::make_pair(STR_EMPTY, true); // default namespace
83 return std::make_pair(STR_EMPTY, false); // none found
86 bool XmlnsStack::PrefixMatchesNs(const std::string& prefix,
87 const std::string& ns) {
88 const std::pair<std::string, bool> match = NsForPrefix(prefix);
89 return match.second && (match.first == ns);
92 std::pair<std::string, bool> XmlnsStack::PrefixForNs(const std::string& ns,
95 return std::make_pair(std::string("xml"), true);
97 return std::make_pair(std::string("xmlns"), true);
98 if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
99 return std::make_pair(STR_EMPTY, true);
101 std::vector<std::string>::iterator pos;
102 for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
104 if (*(pos + 1) == ns &&
105 (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
106 return std::make_pair(*pos, true);
109 return std::make_pair(STR_EMPTY, false); // none found
112 std::string XmlnsStack::FormatQName(const QName& name, bool isAttr) {
113 std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
114 if (prefix == STR_EMPTY)
115 return name.LocalPart();
117 return prefix + ':' + name.LocalPart();
120 void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
121 pxmlnsStack_->push_back(prefix);
122 pxmlnsStack_->push_back(ns);
125 void XmlnsStack::RemoveXmlns() {
126 pxmlnsStack_->pop_back();
127 pxmlnsStack_->pop_back();
130 static bool IsAsciiLetter(char ch) {
131 return ((ch >= 'a' && ch <= 'z') ||
132 (ch >= 'A' && ch <= 'Z'));
135 static std::string AsciiLower(const std::string & s) {
136 std::string result(s);
138 for (i = 0; i < result.length(); i++) {
139 if (result[i] >= 'A' && result[i] <= 'Z')
140 result[i] += 'a' - 'A';
145 static std::string SuggestPrefix(const std::string & ns) {
146 size_t len = ns.length();
147 size_t i = ns.find_last_of('.');
148 if (i != std::string::npos && len - i <= 4 + 1)
149 len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
153 if (IsAsciiLetter(ns[last])) {
157 if (!IsAsciiLetter(ns[first - 1]))
161 if (last - first > 4)
163 std::string candidate(AsciiLower(ns.substr(first, last - first)));
164 if (candidate.find("xml") != 0)
172 std::pair<std::string, bool> XmlnsStack::AddNewPrefix(const std::string& ns,
174 if (PrefixForNs(ns, isAttr).second)
175 return std::make_pair(STR_EMPTY, false);
177 std::string base(SuggestPrefix(ns));
178 std::string result(base);
180 while (NsForPrefix(result).second) {
181 std::stringstream ss;
186 AddXmlns(result, ns);
187 return std::make_pair(result, true);
190 void XmlnsStack::Reset() {
191 pxmlnsStack_->clear();
192 pxmlnsDepthStack_->clear();