224 return xmlStrdup((
const xmlChar *)
"");
226 xmlNode *treeRoot = xmlCopyNode((xmlNode *)tree.
rootXmlNode, 1);
227 VuoDefer(^{ xmlUnlinkNode(treeRoot); xmlFreeNode(treeRoot); });
229 list<xmlNode *> nodesToVisit;
230 nodesToVisit.push_back(treeRoot);
231 while (! nodesToVisit.empty())
233 xmlNode *currentNode = nodesToVisit.front();
234 nodesToVisit.pop_front();
236 if (xmlStrlen(currentNode->name) == 0)
238 const char *name = (currentNode == treeRoot && level == 0 ?
"document" :
"item");
239 xmlNodeSetName(currentNode, (
const xmlChar *)name);
243 int flags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
244 string testElement =
"<" + string((
const char *)currentNode->name) +
"/>";
245 xmlDoc *testDoc = xmlReadMemory(testElement.c_str(), testElement.length(),
"VuoTree.xml",
encoding, flags);
248 xmlNewProp(currentNode, (
const xmlChar *)
"name", (
const xmlChar *)currentNode->name);
249 xmlNodeSetName(currentNode, (
const xmlChar *)
"item");
253 for (xmlNode *n = currentNode->children; n; n = n->next)
254 if (n->type == XML_ELEMENT_NODE)
255 nodesToVisit.push_back(n);
258 xmlBuffer *buffer = xmlBufferCreate();
259 VuoDefer(^{ xmlBufferFree(buffer); });
261 int ret = xmlNodeDump(buffer, treeRoot->doc, treeRoot, level, indent);
265 VUserLog(
"Error: Couldn't serialize tree named '%s' as XML.", treeRoot->name);
266 return xmlStrdup((
const xmlChar *)
"");
269 xmlChar *xml = xmlBufferDetach(buffer);
274 if (xml[xmlStrlen(xml)-2] ==
'/')
277 closingTag = xmlStrdup((
const xmlChar *)
"</");
278 closingTag = xmlStrcat(closingTag, treeRoot->name);
279 closingTag = xmlStrcat(closingTag, (
const xmlChar *)
">");
280 xml[xmlStrlen(xml)-2] =
'>';
281 xml[xmlStrlen(xml)-1] = 0;
286 int closingTagLength = xmlStrlen(treeRoot->name) + 3;
287 int splitIndex = xmlStrlen(xml) - closingTagLength;
288 closingTag = xmlStrsub(xml, splitIndex, closingTagLength);
292 string whitespaceBeforeChild = (indent ?
"\n" + string(2 * (level+1),
' ') :
"");
295 for (
unsigned long i = 1; i <= childCount; ++i)
297 xml = xmlStrcat(xml, (
const xmlChar *)whitespaceBeforeChild.c_str());
301 xml = xmlStrcat(xml, childXml);
304 string whitespaceBeforeClosingTag = (indent ?
"\n" + string(2 * level,
' ') :
"");
305 xml = xmlStrcat(xml, (
const xmlChar *)whitespaceBeforeClosingTag.c_str());
307 xml = xmlStrcat(xml, closingTag);
329 if (! jsonString || strlen(jsonString) == 0)
332 enum json_tokener_error error;
333 json_object *json = json_tokener_parse_verbose(jsonString, &error);
336 VUserLog(
"Error: Couldn't parse tree as JSON: %s", json_tokener_error_desc(error));
341 if (json_object_is_type(json, json_type_object) && json_object_object_length(json) == 1)
344 json_object_object_foreach(json, key, value)
346 if (json_object_is_type(value, json_type_array))
356 json_object *renamedRootObject = NULL;
357 json_object *renamedArrayObject = NULL;
364 if (json_object_is_type(json, json_type_array))
366 json_object *arrayParent = json_object_new_object();
367 json_object_object_add(arrayParent,
"array", json);
369 renamedArrayObject = arrayParent;
372 json_object *parent = json_object_new_object();
373 json_object_object_add(parent,
"json", json);
375 renamedRootObject = parent;
378 xmlDoc *doc = xmlNewDoc((
const xmlChar *)
"1.0");
379 xmlNode *root = NULL;
380 map<json_object *, xmlNode *> parents;
382 list<json_object *> jsonsToVisit;
383 jsonsToVisit.push_back(json);
384 while (! jsonsToVisit.empty())
386 json_object *currentJson = jsonsToVisit.front();
387 jsonsToVisit.pop_front();
389 xmlNode *parentNode = parents[currentJson];
391 json_type type = json_object_get_type(currentJson);
392 if (type == json_type_object)
397 json_object_object_foreach(currentJson, key, value)
399 const char *nodeName = (currentJson == renamedRootObject || currentJson == renamedArrayObject ?
"" : key);
401 if (json_object_is_type(value, json_type_array))
403 int length = json_object_array_length(value);
404 for (
int i = 0; i < length; ++i)
406 json_object *arrayValue = json_object_array_get_idx(value, i);
409 xmlAddChild(parentNode, currentNode);
411 parents[arrayValue] = currentNode;
412 jsonsToVisit.push_back(arrayValue);
420 xmlAddChild(parentNode, currentNode);
424 parents[value] = currentNode;
425 jsonsToVisit.push_back(value);
429 else if (type == json_type_array)
435 int length = json_object_array_length(currentJson);
436 for (
int i = 0; i < length; ++i)
438 json_object *arrayValue = json_object_array_get_idx(currentJson, i);
441 xmlAddChild(parentNode, currentNode);
443 parents[arrayValue] = currentNode;
444 jsonsToVisit.push_back(arrayValue);
449 const char *content = json_object_get_string(currentJson);
450 xmlChar *encoded = xmlEncodeSpecialChars(doc, (
const xmlChar *)content);
451 xmlNodeSetContent(parentNode, encoded);
456 xmlDocSetRootElement(doc, root);
458 json_object_put(json);
462 tree.
rootJson = json_tokener_parse(jsonString);
523 json_object *topLevelJson = json_object_new_object();
524 const char *topLevelName = (xmlStrlen(rootNode->name) > 0 ? (
const char *)rootNode->name : (atRoot ?
"document" :
"item"));
526 map<xmlNode *, json_object *> containers;
527 containers[rootNode] = topLevelJson;
529 map<xmlNode *, const char *> names;
530 names[rootNode] = topLevelName;
532 list<xmlNode *> nodesToVisit;
533 nodesToVisit.push_back( (xmlNode *)tree.
rootXmlNode );
534 while (! nodesToVisit.empty())
536 xmlNode *currentNode = nodesToVisit.front();
537 nodesToVisit.pop_front();
543 vector< pair<const char *, ChildInfo> > childInfos;
544 int elementCount = 0;
547 for (xmlAttr *attribute = currentNode->properties; attribute; attribute = attribute->next)
549 xmlChar *attributeValue = xmlNodeListGetString(rootNode->doc, attribute->children, 1);
550 ChildInfo info = { NULL, (
const char *)attributeValue };
551 childInfos.push_back(make_pair( (
const char *)attribute->name, info ));
554 for (xmlNode *childNode = currentNode->children; childNode; childNode = childNode->next)
556 if (childNode->type == XML_ELEMENT_NODE)
558 const char *childName = (xmlStrlen(childNode->name) > 0 ? (
const char *)childNode->name :
"item");
559 names[childNode] = childName;
562 childInfos.push_back(make_pair( childName, info ));
566 else if (childNode->type == XML_TEXT_NODE || childNode->type == XML_CDATA_SECTION_NODE)
568 ChildInfo info = { childNode, (
char *)childNode->content };
569 childInfos.push_back(make_pair( (
const char *)NULL, info ));
575 json_object *currentContainer = containers[currentNode];
576 const char *currentName = names[currentNode];
578 if (childInfos.empty())
585 else if (childInfos.size() == 1 && childInfos[0].first == NULL)
597 vector< pair<const char *, vector<ChildInfo> > > mergedChildInfo;
598 map<size_t, bool> childInfosVisited;
600 for (
size_t i = 0; i < childInfos.size(); ++i)
602 if (childInfosVisited[i])
605 vector<ChildInfo> sameNameInfo;
606 sameNameInfo.push_back(childInfos[i].second);
607 childInfosVisited[i] =
true;
609 if (childInfos[i].first)
611 for (
size_t j = i+1; j < childInfos.size(); ++j)
613 if (! childInfos[j].first)
616 if (! strcmp(childInfos[i].first, childInfos[j].first))
618 sameNameInfo.push_back(childInfos[j].second);
619 childInfosVisited[j] =
true;
624 mergedChildInfo.push_back(make_pair( childInfos[i].first, sameNameInfo ));
630 bool isMixedContent = elementCount > 0 && textCount > 0;
631 json_object *childContainer = (isMixedContent ? json_object_new_array() : json_object_new_object());
635 for (vector< pair<
const char *, vector<ChildInfo> > >::iterator i = mergedChildInfo.begin(); i != mergedChildInfo.end(); ++i)
637 if ((*i).second.size() == 1)
641 if ((*i).second[0].text)
644 const char *childName = ((*i).first ? (*i).first :
"content");
649 json_object *singleChildContainer;
652 singleChildContainer = json_object_new_object();
653 json_object_array_add(childContainer, singleChildContainer);
656 singleChildContainer = childContainer;
658 containers[(*i).second[0].node] = singleChildContainer;
665 json_object *sameNameArray = json_object_new_array();
666 for (vector<ChildInfo>::iterator j = (*i).second.begin(); j != (*i).second.end(); ++j)
671 json_object_array_add(sameNameArray, text);
674 containers[(*j).node] = sameNameArray;
677 json_object *sameNameArrayContainer;
680 sameNameArrayContainer = json_object_new_object();
681 json_object_array_add(childContainer, sameNameArrayContainer);
684 sameNameArrayContainer = childContainer;
686 const char *childName = ((*i).first ? (*i).first :
"content");
693 for (xmlNode *childNode = currentNode->children; childNode; childNode = childNode->next)
694 if (childNode->type == XML_ELEMENT_NODE)
695 nodesToVisit.push_back(childNode);
700 const char *rootKey = NULL;
701 json_object *rootValue = NULL;
702 json_object_object_foreach(topLevelJson, key, value)
712 rootValue = json_object_new_object();
713 json_object_object_add(topLevelJson, rootKey, rootValue);
717 for (
unsigned long i = 1; i <= childCount; ++i)
725 const char *childKey = NULL;
726 json_object *childValue = NULL;
727 json_object_object_foreach(childJson, key, value)
734 json_object *siblingValue = NULL;
735 if (json_object_object_get_ex(rootValue, childKey, &siblingValue))
737 if (! json_object_is_type(siblingValue, json_type_array))
740 json_object *siblingsArray = json_object_new_array();
741 json_object_get(siblingValue);
742 json_object_array_add(siblingsArray, siblingValue);
743 json_object_object_add(rootValue, childKey, siblingsArray);
744 siblingValue = siblingsArray;
748 json_object_array_add(siblingValue, childValue);
753 json_object_object_add(rootValue, childKey, childValue);
1190 VuoTree treeIncludingChildren;
1201 treeIncludingChildren = tree;
1205 xmlNode *treeRoot = (xmlNode *)treeIncludingChildren.
rootXmlNode;
1210 xmlXPathContext *xpathContext = xmlXPathNewContext(treeRoot->doc);
1213 VUserLog(
"Error: Couldn't create xmlXPathContext");
1216 VuoDefer(^{ xmlXPathFreeContext(xpathContext); });
1219 const int numSmartquotes = 4;
1220 const char *smartquotes[numSmartquotes] = {
"“",
"”",
"‘",
"’" };
1221 const char *plainquotes[numSmartquotes] = {
"\"",
"\"",
"'",
"'" };
1222 VuoText requotedXpaths[numSmartquotes];
1223 for (
int i = 0; i < numSmartquotes; ++i)
1225 requotedXpaths[i] =
VuoText_replace(xpath, smartquotes[i], plainquotes[i]);
1226 xpath = requotedXpaths[i];
1228 VuoText *requotedXPathsPtr = requotedXpaths;
1230 for (
int i = 0; i < numSmartquotes; ++i)
1232 if (requotedXPathsPtr[i] != xpath)
1241 int ret = xmlXPathSetContextNode(treeRoot, xpathContext);
1244 VUserLog(
"Error: Couldn't set context node to '%s'", treeRoot->name);
1249 bool isSubtree = (treeRoot != xmlDocGetRootElement(treeRoot->doc));
1251 xmlChar *prefixedXpath;
1252 if (isSubtree && xpath[0] ==
'/')
1255 xmlChar *xpathPrefix = xmlStrdup((
const xmlChar *)
"");
1256 for (xmlNode *parent = treeRoot->parent; parent; parent = parent->parent)
1258 if (parent->type == XML_ELEMENT_NODE)
1260 xpathPrefix = xmlStrcat(xmlStrdup(parent->name), xpathPrefix);
1261 xpathPrefix = xmlStrcat(xmlStrdup((
const xmlChar *)
"/"), xpathPrefix);
1264 prefixedXpath = xmlStrcat(xpathPrefix, (
const xmlChar *)xpath);
1268 prefixedXpath = xmlStrdup((
const xmlChar *)xpath);
1270 VuoDefer(^{ xmlFree(prefixedXpath); });
1273 xmlXPathObject *xpathObject = xmlXPathEvalExpression(prefixedXpath, xpathContext);
1276 VUserLog(
"Error: Couldn't evaluate XPath expression '%s'", prefixedXpath);
1279 VuoDefer(^{ xmlXPathFreeObject(xpathObject); });
1281 if (xmlXPathNodeSetIsEmpty(xpathObject->nodesetval))
1285 vector<xmlNode *> foundNodes;
1286 map<xmlNode *, vector<xmlNode *> > attributesForFoundNode;
1287 for (
int i = 0; i < xpathObject->nodesetval->nodeNr; ++i)
1289 xmlNode *foundNode = xpathObject->nodesetval->nodeTab[i];
1291 if (foundNode->type == XML_ATTRIBUTE_NODE || foundNode->type == XML_TEXT_NODE || foundNode->type == XML_CDATA_SECTION_NODE)
1293 if (find(foundNodes.begin(), foundNodes.end(), foundNode->parent) == foundNodes.end())
1294 foundNodes.push_back(foundNode->parent);
1296 if (foundNode->type == XML_ATTRIBUTE_NODE)
1297 attributesForFoundNode[foundNode->parent].push_back(foundNode);
1299 else if (foundNode->type == XML_ELEMENT_NODE)
1301 foundNodes.push_back(foundNode);
1307 for (vector<xmlNode *>::iterator i = foundNodes.begin(); i != foundNodes.end(); ++i)
1309 xmlNode *foundNode = *i;
1314 bool isNodeInTree =
false;
1315 for (xmlNode *n = foundNode; n; n = n->parent)
1319 isNodeInTree =
true;
1328 map<xmlNode *, vector<xmlNode *> >::iterator attributesIter = attributesForFoundNode.find(foundNode);
1329 if (attributesIter == attributesForFoundNode.end())
1338 for (vector<xmlNode *>::iterator j = attributesIter->second.begin(); j != attributesIter->second.end(); ++j)
1340 xmlNode *foundAttribute = *j;
1345 foundTree =
VuoTree_make((
const char *)foundNode->name, attributes,
"", NULL);