1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012-2014 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #include "XMLObject.hxx"
17 #include "XMLElement.hxx"
18 #include "XMLDocument.hxx"
19 #include "XMLNodeList.hxx"
20 #include "XMLNs.hxx"
21 #include "XMLAttr.hxx"
22 #include "VariableScope.hxx"
23 
24 extern "C"
25 {
26     extern const char *nodes_type[];
27 }
28 
29 namespace org_modules_xml
30 {
31 
XMLElement(const XMLDocument & _doc,xmlNode * _node)32 XMLElement::XMLElement(const XMLDocument & _doc, xmlNode * _node): XMLObject(), allocated(false), doc(_doc)
33 {
34     node = _node;
35     scope->registerPointers(node, this);
36     scilabType = XMLELEMENT;
37     id = scope->getVariableId(*this);
38 }
39 
XMLElement(const XMLDocument & _doc,const char * name)40 XMLElement::XMLElement(const XMLDocument & _doc, const char *name): XMLObject(), allocated(true), doc(_doc)
41 {
42     node = xmlNewNode(0, (const xmlChar *)name);
43     scope->registerPointers(node, this);
44     scilabType = XMLELEMENT;
45     id = scope->getVariableId(*this);
46 }
47 
~XMLElement()48 XMLElement::~XMLElement()
49 {
50     scope->unregisterPointer(node);
51     scope->removeId(id);
52 
53     if (allocated)
54     {
55         xmlFreeNode(node);
56     }
57 }
58 
getRealXMLPointer() const59 void *XMLElement::getRealXMLPointer() const
60 {
61     return static_cast < void *>(node);
62 }
63 
remove() const64 void XMLElement::remove() const
65 {
66     XMLNodeList *obj = 0;
67 
68     if (node->parent && node->parent->children)
69     {
70         obj = scope->getXMLNodeListFromLibXMLPtr(node->parent->children);
71         if (obj && node->parent->children == node)
72         {
73             // node->parent->children == node => we remove the first child so parent->children
74             // needs to be correctly re-linked.
75             obj->removeElementAtPosition(1);
76             return;
77         }
78     }
79 
80     xmlUnlinkNode(node);
81     xmlFreeNode(node);
82 
83     if (obj)
84     {
85         obj->revalidateSize();
86     }
87 }
88 
getXMLObjectParent() const89 const XMLObject *XMLElement::getXMLObjectParent() const
90 {
91     return &doc;
92 }
93 
getNodeContent() const94 const char *XMLElement::getNodeContent() const
95 {
96     return (const char *)xmlNodeGetContent(node);
97 }
98 
setNodeName(const std::string & name) const99 void XMLElement::setNodeName(const std::string & name) const
100 {
101     xmlNodeSetName(node, (const xmlChar *)name.c_str());
102 }
103 
setNodeNameSpace(const XMLNs & ns) const104 void XMLElement::setNodeNameSpace(const XMLNs & ns) const
105 {
106     xmlNs *n = ns.getRealNs();
107     if (n)
108     {
109         if (!n->prefix || !xmlSearchNs(doc.getRealDocument(), node, n->prefix))
110         {
111             n = xmlNewNs(node, (const xmlChar *)ns.getHref(), (const xmlChar *)ns.getPrefix());
112         }
113         xmlSetNs(node, n);
114     }
115 }
116 
setNodeContent(const std::string & content) const117 void XMLElement::setNodeContent(const std::string & content) const
118 {
119     xmlNodeSetContent(node, (const xmlChar *)content.c_str());
120 }
121 
setAttributes(const XMLAttr & attrs) const122 void XMLElement::setAttributes(const XMLAttr & attrs) const
123 {
124     xmlNode *attrNode = attrs.getElement().getRealNode();
125     if (node != attrNode)
126     {
127         xmlFreePropList(node->properties);
128         node->properties = 0;
129         xmlCopyPropList(node, attrNode->properties);
130     }
131 }
132 
setAttributeValue(const char ** prefix,const char ** name,const char ** value,int size) const133 void XMLElement::setAttributeValue(const char **prefix, const char **name, const char **value, int size) const
134 {
135     XMLAttr::setAttributeValue(node, prefix, name, value, size);
136 }
137 
setAttributeValue(const char ** name,const char ** value,int size) const138 void XMLElement::setAttributeValue(const char **name, const char **value, int size) const
139 {
140     XMLAttr::setAttributeValue(node, name, value, size);
141 }
142 
append(const XMLElement & elem) const143 void XMLElement::append(const XMLElement & elem) const
144 {
145     XMLNodeList * list = 0;
146     xmlNode *cpy = xmlCopyNode(elem.getRealNode(), 1);
147     xmlUnlinkNode(cpy);
148     xmlAddChild(node, cpy);
149 
150     list = scope->getXMLNodeListFromLibXMLPtr(node->children);
151     if (list)
152     {
153         list->incrementSize();
154     }
155 }
156 
setChildren(const XMLElement & elem) const157 void XMLElement::setChildren(const XMLElement & elem) const
158 {
159     xmlNode *n = elem.getRealNode();
160     if (n && n->parent != node)
161     {
162         xmlNode *cpy = xmlCopyNode(n, 1);
163         xmlUnlinkNode(cpy);
164         xmlUnlinkNode(node->children);
165         xmlFreeNodeList(node->children);
166         node->children = 0;
167         xmlAddChild(node, cpy);
168     }
169 }
170 
setChildren(const XMLNodeList & list) const171 void XMLElement::setChildren(const XMLNodeList & list) const
172 {
173     xmlNode *n = list.getRealNode();
174     if (n && n->parent != node)
175     {
176         xmlNode *cpy = xmlCopyNodeList(n);
177         xmlUnlinkNode(node->children);
178         xmlFreeNodeList(node->children);
179         node->children = 0;
180         xmlAddChildList(node, cpy);
181     }
182 }
183 
setChildren(const std::string & xmlCode) const184 void XMLElement::setChildren(const std::string & xmlCode) const
185 {
186     std::string error;
187     XMLDocument document = XMLDocument(xmlCode, false, &error);
188 
189     if (error.empty())
190     {
191         setChildren(*document.getRoot());
192     }
193     else
194     {
195         xmlNode *n = xmlNewText((xmlChar *) xmlCode.c_str());
196 
197         setChildren(XMLElement(doc, n));
198     }
199 }
200 
addNamespace(const XMLNs & ns) const201 void XMLElement::addNamespace(const XMLNs & ns) const
202 {
203     xmlNewNs(node, (const xmlChar *)ns.getHref(), (const xmlChar *)ns.getPrefix());
204 }
205 
getNamespaceByPrefix(const char * prefix) const206 const XMLNs *XMLElement::getNamespaceByPrefix(const char *prefix) const
207 {
208     xmlNs *ns = xmlSearchNs(doc.getRealDocument(), node, (const xmlChar *)prefix);
209     XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(ns);
210     if (obj)
211     {
212         return static_cast < XMLNs * >(obj);
213     }
214 
215     return new XMLNs(*this, ns);
216 }
217 
getNamespaceByHref(const char * href) const218 const XMLNs *XMLElement::getNamespaceByHref(const char *href) const
219 {
220     xmlNs *ns = xmlSearchNsByHref(doc.getRealDocument(), node, (const xmlChar *)href);
221     XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(ns);
222     if (obj)
223     {
224         return static_cast < XMLNs * >(obj);
225     }
226 
227     return new XMLNs(*this, ns);
228 }
229 
dump(bool indent) const230 const std::string XMLElement::dump(bool indent) const
231 {
232     xmlBufferPtr buffer = xmlBufferCreate();
233     xmlNodeDump(buffer, doc.getRealDocument(), node, 0, indent ? 1 : 0);
234     std::string str = std::string((const char *)buffer->content);
235     xmlBufferFree(buffer);
236 
237     return str;
238 }
239 
toString() const240 const std::string XMLElement::toString() const
241 {
242     std::ostringstream oss;
243     std::string ns = "";
244     std::string prefix = "";
245 
246     if (node->ns)
247     {
248         if (node->ns->href)
249         {
250             ns = std::string((const char *)node->ns->href);
251         }
252 
253         if (node->ns->prefix)
254         {
255             prefix = std::string((const char *)node->ns->prefix);
256         }
257     }
258 
259     oss << "XML Element" << std::endl
260         << "name: " << getNodeName() << std::endl
261         << "namespace: XML Namespace" << std::endl
262         << "    href: " << ns << std::endl
263         << "    prefix: " << prefix << std::endl
264         << "type: " << nodes_type[getNodeType() - 1] << std::endl
265         << "parent: XML Element" << std::endl
266         << "attributes: [1 x " << XMLAttr::getSize(node->properties) << "]" << std::endl
267         << "children: [1 x " << XMLNodeList::getNodeListSize(node->children) << "]" << std::endl
268         << "content: ..." << std::endl
269         << "line: " << node->line;
270 
271     return oss.str();
272 }
273 
getDefinitionLine() const274 int XMLElement::getDefinitionLine() const
275 {
276     return node->line;
277 }
278 
getNodeNameSpace() const279 const XMLNs *XMLElement::getNodeNameSpace() const
280 {
281     if (node->ns)
282     {
283         XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(node->ns);
284         if (obj)
285         {
286             return static_cast < XMLNs * >(obj);
287         }
288 
289         return new XMLNs(*this, node->ns);
290     }
291     else
292     {
293         return 0;
294     }
295 }
296 
getChildren() const297 const XMLNodeList *XMLElement::getChildren() const
298 {
299     XMLNodeList *obj = scope->getXMLNodeListFromLibXMLPtr(node->children);
300     if (obj)
301     {
302         return obj;
303     }
304 
305     return new XMLNodeList(doc, node);
306 }
307 
getAttributes() const308 const XMLAttr *XMLElement::getAttributes() const
309 {
310     XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(node->properties);
311     if (obj)
312     {
313         return static_cast < XMLAttr * >(obj);
314     }
315 
316     return new XMLAttr(*this);
317 }
318 
getParentElement() const319 const XMLElement *XMLElement::getParentElement() const
320 {
321     if (node->parent && node->parent->type == XML_ELEMENT_NODE)
322     {
323         XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(node->parent);
324         if (obj)
325         {
326             return static_cast < XMLElement * >(obj);
327         }
328 
329         return new XMLElement(doc, node->parent);
330     }
331     else
332     {
333         return 0;
334     }
335 }
336 }
337