00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #include "element.h"
00037 #include "tools.h"
00038
00039 #include <string.h>
00040
00041 using namespace zmm;
00042 using namespace mxml;
00043
00044 Element::Element(String name) : Node()
00045 {
00046 type = mxml_node_element;
00047 this->name = name;
00048 arrayType = false;
00049 arrayName = nil;
00050 textKey = nil;
00051 }
00052 Element::Element(String name, Ref<Context> context) : Node()
00053 {
00054 type = mxml_node_element;
00055 this->name = name;
00056 this->context = context;
00057 arrayType = false;
00058 arrayName = nil;
00059 textKey = nil;
00060 }
00061 String Element::getAttribute(String name)
00062 {
00063 if(attributes == nil)
00064 return nil;
00065 int len = attributes->size();
00066 for(int i = 0; i < len; i++)
00067 {
00068 Ref<Attribute> attr = attributes->get(i);
00069 if(attr->name == name)
00070 return attr->value;
00071 }
00072 return nil;
00073 }
00074 void Element::addAttribute(String name, String value, enum mxml_value_type type)
00075 {
00076 Ref<Attribute> attr = Ref<Attribute>(new Attribute(name, value, type));
00077 addAttribute(attr);
00078 }
00079
00080 void Element::addAttribute(Ref<Attribute> attr)
00081 {
00082 if (attributes == nil)
00083 attributes = Ref<Array<Attribute> >(new Array<Attribute>());
00084 attributes->append(attr);
00085 }
00086
00087 void Element::setAttribute(String name, String value, enum mxml_value_type type)
00088 {
00089 if (attributes == nil)
00090 attributes = Ref<Array<Attribute> >(new Array<Attribute>());
00091 int len = attributes->size();
00092 for(int i = 0; i < len; i++)
00093 {
00094 Ref<Attribute> attr = attributes->get(i);
00095 if(attr->name == name)
00096 {
00097 attr->setValue(value);
00098 attr->setVType(type);
00099 return;
00100 }
00101 }
00102 addAttribute(name, value, type);
00103 }
00104
00105 int Element::childCount(enum mxml_node_types type)
00106 {
00107 if (children == nil)
00108 return 0;
00109
00110 if (type == mxml_node_all)
00111 return children->size();
00112
00113 int countElements = 0;
00114 for(int i = 0; i < children->size(); i++)
00115 {
00116 Ref<Node> nd = children->get(i);
00117 if (nd->getType() == type)
00118 {
00119 countElements++;
00120 }
00121 }
00122 return countElements;
00123 }
00124
00125 Ref<Node> Element::getChild(int index, enum mxml_node_types type, bool remove)
00126 {
00127 if (children == nil)
00128 return nil;
00129 int countElements = 0;
00130
00131 if (type == mxml_node_all)
00132 {
00133 if (index >= children->size())
00134 return nil;
00135 else
00136 {
00137 Ref<Node> node = children->get(index);
00138 if (remove)
00139 children->remove(index);
00140 return node;
00141 }
00142 }
00143
00144 for(int i = 0; i < children->size(); i++)
00145 {
00146 Ref<Node> nd = children->get(i);
00147 if (nd->getType() == type)
00148 {
00149 if (countElements++ == index)
00150 {
00151 if (remove)
00152 children->remove(i);
00153 return nd;
00154 }
00155 }
00156 }
00157 return nil;
00158 }
00159
00160 bool Element::removeElementChild(String name, bool removeAll)
00161 {
00162 int id = getChildIdByName(name);
00163 if (id < 0)
00164 return false;
00165 Ref<Node> child = getChild(id, mxml_node_all, true);
00166 if (child == nil)
00167 return false;
00168 if (! removeAll)
00169 return true;
00170 removeElementChild(name, true);
00171 return true;
00172 }
00173
00174 void Element::appendChild(Ref<Node> child)
00175 {
00176 if(children == nil)
00177 children = Ref<Array<Node> >(new Array<Node>());
00178 children->append(child);
00179 }
00180
00181 void Element::insertChild(int index, Ref<Node> child)
00182 {
00183 if (children == nil)
00184 children = Ref<Array<Node> >(new Array<Node>());
00185 children->insert(index, child);
00186 }
00187
00188 void Element::removeChild(int index, enum mxml_node_types type)
00189 {
00190 if (type == mxml_node_all)
00191 children->remove(index);
00192 else
00193 {
00194 getChild(index, type, true);
00195 }
00196 }
00197
00198 void Element::removeWhitespace()
00199 {
00200 int numChildren = childCount();
00201 for (int i = 0; i < numChildren; i++)
00202 {
00203 Ref<Node> node = getChild(i);
00204 if (node->getType() == mxml_node_text)
00205 {
00206 Ref<Text> text = RefCast(node, Text);
00207 String trimmed = trim_string(text->getText());
00208 if (string_ok(trimmed))
00209 {
00210 text->setText(trimmed);
00211 }
00212 else
00213 {
00214 if (numChildren != 1)
00215 {
00216 removeChild(i--);
00217 --numChildren;
00218 }
00219 }
00220 }
00221 else if (node->getType() == mxml_node_element)
00222 {
00223 Ref<Element> el = RefCast(node, Element);
00224 el->removeWhitespace();
00225 }
00226 }
00227 }
00228
00229 void Element::indent(int level)
00230 {
00231 assert(level >= 0);
00232
00233 removeWhitespace();
00234
00235 int numChildren = childCount();
00236 if (! numChildren)
00237 return;
00238
00239 bool noTextChildren = true;
00240 for (int i = 0; i < numChildren; i++)
00241 {
00242 Ref<Node> node = getChild(i);
00243 if (node->getType() == mxml_node_element)
00244 {
00245 Ref<Element> el = RefCast(node, Element);
00246 el->indent(level+1);
00247 }
00248 else if (node->getType() == mxml_node_text)
00249 {
00250 noTextChildren = false;
00251 }
00252 }
00253
00254 if (noTextChildren)
00255 {
00256 static const char *ind_str = " ";
00257 static const char *ind = ind_str + strlen(ind_str);
00258 const char *ptr = ind - (level + 1) * 2;
00259 if (ptr < ind_str)
00260 ptr = ind_str;
00261
00262 for (int i = 0; i < numChildren; i++)
00263 {
00264 bool newlineBefore = true;
00265 if (getChild(i)->getType() == mxml_node_comment)
00266 {
00267 Ref<Comment> comment = RefCast(getChild(i), Comment);
00268 newlineBefore = comment->getIndentWithLFbefore();
00269 }
00270 if (newlineBefore)
00271 {
00272 Ref<Text> indentText(new Text(_("\n")+ptr));
00273 insertChild(i++,RefCast(indentText, Node));
00274 numChildren++;
00275 }
00276 }
00277
00278 ptr += 2;
00279
00280 Ref<Text> indentTextAfter(new Text(_("\n")+ptr));
00281 appendChild(RefCast(indentTextAfter, Node));
00282 }
00283 }
00284
00285 String Element::getText()
00286 {
00287 Ref<StringBuffer> buf(new StringBuffer());
00288 Ref<Text> text;
00289 int i = 0;
00290 bool someText = false;
00291 while ((text = RefCast(getChild(i++, mxml_node_text), Text)) != nil)
00292 {
00293 someText = true;
00294 *buf << text->getText();
00295 }
00296 if (someText)
00297 return buf->toString();
00298 else
00299 return nil;
00300 }
00301
00302 enum mxml_value_type Element::getVTypeText()
00303 {
00304 Ref<Text> text;
00305 int i = 0;
00306 bool someText = false;
00307 enum mxml_value_type vtype = mxml_string_type;
00308 while ((text = RefCast(getChild(i++, mxml_node_text), Text)) != nil)
00309 {
00310 if (! someText)
00311 {
00312 someText = true;
00313 vtype = text->getVType();
00314 }
00315 else
00316 {
00317 if (vtype != text->getVType())
00318 vtype = mxml_string_type;
00319 }
00320 }
00321 return vtype;
00322 }
00323
00324 int Element::attributeCount()
00325 {
00326 if (attributes == nil)
00327 return 0;
00328 return attributes->size();
00329 }
00330
00331 Ref<Attribute> Element::getAttribute(int index)
00332 {
00333 if (attributes == nil)
00334 return nil;
00335 if (index >= attributes->size())
00336 return nil;
00337 return attributes->get(index);
00338 }
00339
00340 void Element::setText(String str, enum mxml_value_type type)
00341 {
00342 if (childCount() > 1)
00343 throw _Exception(_("Element::setText() cannot be called on an element which has more than one child"));
00344
00345 if (childCount() == 1)
00346 {
00347 Ref<Node> child = getChild(0);
00348 if (child == nil || child->getType() != mxml_node_text)
00349 throw _Exception(_("Element::setText() cannot be called on an element which has a non-text child"));
00350 Ref<Text> text = RefCast(child, Text);
00351 text->setText(str);
00352 }
00353 else
00354 {
00355 Ref<Text> text(new Text(str, type));
00356 appendChild(RefCast(text, Node));
00357 }
00358 }
00359
00360 void Element::appendTextChild(String name, String text, enum mxml_value_type type)
00361 {
00362 Ref<Element> el = Ref<Element>(new Element(name));
00363 el->setText(text, type);
00364 appendElementChild(el);
00365 }
00366
00367
00368
00369 int Element::getChildIdByName(String name)
00370 {
00371 if(children == nil)
00372 return -1;
00373 for(int i = 0; i < children->size(); i++)
00374 {
00375 Ref<Node> nd = children->get(i);
00376 if (nd->getType() == mxml_node_element)
00377 {
00378 Ref<Element> el = RefCast(nd, Element);
00379 if (name == nil || el->name == name)
00380 return i;
00381 }
00382 }
00383 return -1;
00384 }
00385
00386 Ref<Element> Element::getChildByName(String name)
00387 {
00388 int id = getChildIdByName(name);
00389 if (id < 0)
00390 return nil;
00391 return RefCast(getChild(id), Element);
00392 }
00393
00394 String Element::getChildText(String name)
00395 {
00396 Ref<Element> el = getChildByName(name);
00397 if(el == nil)
00398 return nil;
00399 return el->getText();
00400 }
00401
00402 void Element::print_internal(Ref<StringBuffer> buf, int indent)
00403 {
00404
00405
00406
00407
00408
00409
00410
00411 int i;
00412
00413 *buf << "<" << name;
00414 if (attributes != nil)
00415 {
00416 for(i = 0; i < attributes->size(); i++)
00417 {
00418 *buf << ' ';
00419 Ref<Attribute> attr = attributes->get(i);
00420 *buf << attr->name << "=\"" << escape(attr->value) << '"';
00421 }
00422 }
00423
00424 if (children != nil && children->size())
00425 {
00426 *buf << ">";
00427
00428 for(i = 0; i < children->size(); i++)
00429 {
00430 children->get(i)->print_internal(buf, indent + 1);
00431 }
00432
00433 *buf << "</" << name << ">";
00434 }
00435 else
00436 {
00437 *buf << "/>";
00438 }
00439 }