35 |
35 |
36 #include "../util/util.h" |
36 #include "../util/util.h" |
37 |
37 |
38 #include "xml.h" |
38 #include "xml.h" |
39 |
39 |
40 /* ------------------------ utils ------------------------ */ |
40 /***************************************************************************** |
|
41 * Utility functions |
|
42 *****************************************************************************/ |
41 |
43 |
42 /* |
44 /* |
43 * generates a string key for an xml namespace |
45 * generates a string key for an xml namespace |
44 * format: prefix '\0' href |
46 * format: prefix '\0' href |
45 */ |
47 */ |
46 static sstr_t namespace_key(UcxAllocator *a, WSNamespace *ns) { |
48 static sstr_t xml_namespace_key(UcxAllocator *a, WSNamespace *ns) { |
47 sstr_t key = sstrcat_a(a, 3, |
49 sstr_t key = sstrcat_a(a, 3, |
48 ns->prefix ? sstr((char*)ns->prefix) : S("\0"), |
50 ns->prefix ? sstr((char*)ns->prefix) : S("\0"), |
49 S("\0"), |
51 S("\0"), |
50 sstr((char*)ns->href)); |
52 sstr((char*)ns->href)); |
51 return key; |
53 return key; |
52 } |
54 } |
53 |
55 |
|
56 |
|
57 /***************************************************************************** |
|
58 * Public functions |
|
59 *****************************************************************************/ |
54 |
60 |
55 /* ------------------------ wsxml_iterator ------------------------ */ |
61 /* ------------------------ wsxml_iterator ------------------------ */ |
56 |
62 |
57 typedef struct StackElm { |
63 typedef struct StackElm { |
58 WSXmlNode *node; // list of nodes |
64 WSXmlNode *node; // list of nodes |
303 } |
309 } |
304 |
310 |
305 ucx_map_free(nsmap); |
311 ucx_map_free(nsmap); |
306 return list; |
312 return list; |
307 } |
313 } |
|
314 |
|
315 |
|
316 /***************************************************************************** |
|
317 * Non public functions |
|
318 *****************************************************************************/ |
|
319 |
|
320 typedef struct XmlWriter { |
|
321 /* |
|
322 * Memory pool for temp memory allocations |
|
323 */ |
|
324 pool_handle_t *pool; |
|
325 |
|
326 /* |
|
327 * Buffered output stream |
|
328 */ |
|
329 Writer *out; |
|
330 |
|
331 /* |
|
332 * Map for all previously defined namespaces |
|
333 * key: (char*) namespace prefix |
|
334 * value: WSNamespace* |
|
335 */ |
|
336 UcxMap *namespaces; |
|
337 |
|
338 /* |
|
339 * Should namespace definitions be created |
|
340 */ |
|
341 WSBool define_namespaces; |
|
342 } XmlWriter; |
|
343 |
|
344 /* |
|
345 * Serialize an XML text node |
|
346 * This replaces some special characters with entity refs |
|
347 */ |
|
348 static void xml_ser_text(Writer *out, const char *text) { |
|
349 size_t start = 0; |
|
350 size_t i; |
|
351 sstr_t entityref = { NULL, 0 }; |
|
352 for(i=0;text[i]!='\0';i++) { |
|
353 switch(text[i]) { |
|
354 case '<': entityref = S("<"); break; |
|
355 case '>': entityref = S(">"); break; |
|
356 case '&': entityref = S("&"); break; |
|
357 case '\"': entityref = S("""); break; |
|
358 case '\'': entityref = S("'"); break; |
|
359 } |
|
360 if(entityref.ptr) { |
|
361 size_t len = i-start; |
|
362 if(len > 0) { |
|
363 writer_put(out, text+start, len); |
|
364 } |
|
365 writer_puts(out, entityref); |
|
366 entityref.ptr = NULL; |
|
367 entityref.length = 0; |
|
368 start = i+1; |
|
369 } |
|
370 } |
|
371 size_t len = i-start; |
|
372 if(len > 0) { |
|
373 writer_put(out, text+start, len); |
|
374 } |
|
375 } |
|
376 |
|
377 /* |
|
378 * Serialize an XML element node |
|
379 */ |
|
380 static void xml_ser_element(XmlWriter *xw, xmlNode *node) { |
|
381 Writer *out = xw->out; |
|
382 writer_putc(out, '<'); |
|
383 |
|
384 // write prefix and ':' |
|
385 if(node->ns && node->ns->prefix) { |
|
386 writer_puts(out, sstr((char*)node->ns->prefix)); |
|
387 writer_putc(out, ':'); |
|
388 } |
|
389 |
|
390 // node name |
|
391 writer_puts(out, sstr((char*)node->name)); |
|
392 |
|
393 // namespace definitions |
|
394 if(xw->define_namespaces) { |
|
395 xmlNs *nsdef = node->nsDef; |
|
396 while(nsdef) { |
|
397 // we define only namespaces without prefix or namespaces |
|
398 // with prefix, that are not already defined |
|
399 // xw->namespaces contains all namespace, that were defined |
|
400 // before xml serialization |
|
401 if(!nsdef->prefix) { |
|
402 writer_puts(out, S(" xmlns=\"")); |
|
403 writer_puts(out, sstr((char*)nsdef->href)); |
|
404 writer_putc(out, '"'); |
|
405 } else { |
|
406 WSNamespace *n = xw->namespaces ? |
|
407 ucx_map_cstr_get(xw->namespaces, (char*)nsdef->prefix) : |
|
408 NULL; |
|
409 if(!n) { |
|
410 writer_puts(out, S(" xmlns:")); |
|
411 writer_puts(out, sstr((char*)nsdef->prefix)); |
|
412 writer_puts(out, S("=\"")); |
|
413 writer_puts(out, sstr((char*)nsdef->href)); |
|
414 writer_putc(out, '"'); |
|
415 } |
|
416 } |
|
417 |
|
418 nsdef = nsdef->next; |
|
419 } |
|
420 } |
|
421 |
|
422 // attributes |
|
423 xmlAttr *attr = node->properties; |
|
424 while(attr) { |
|
425 // format: ' [<prefix>:]<name>="<value>"' |
|
426 writer_putc(out, ' '); |
|
427 // optional namespace |
|
428 if(attr->ns && attr->ns->prefix) { |
|
429 writer_puts(out, sstr((char*)attr->ns->prefix)); |
|
430 writer_putc(out, ':'); |
|
431 } |
|
432 // <name>=" |
|
433 writer_puts(out, sstr((char*)attr->name)); |
|
434 writer_puts(out, S("=\"")); |
|
435 // value |
|
436 xmlNode *value = attr->children; |
|
437 while(value) { |
|
438 if(value->content) { |
|
439 xml_ser_text(out, (const char*)value->content); |
|
440 } |
|
441 value = value->next; |
|
442 } |
|
443 // trailing quote |
|
444 writer_putc(out, '"'); |
|
445 |
|
446 attr = attr->next; |
|
447 } |
|
448 |
|
449 if(node->children) { |
|
450 writer_putc(out, '>'); |
|
451 } else { |
|
452 writer_puts(out, S("/>")); |
|
453 } |
|
454 } |
|
455 |
|
456 static int xml_ser_node_begin(xmlNode *node, void *userdata) { |
|
457 XmlWriter *xw = userdata; |
|
458 switch(node->type) { |
|
459 case XML_ELEMENT_NODE: xml_ser_element(xw, node); break; |
|
460 case XML_ATTRIBUTE_NODE: break; |
|
461 case XML_TEXT_NODE: { |
|
462 xml_ser_text(xw->out, (const char*)node->content); |
|
463 break; |
|
464 } |
|
465 case XML_CDATA_SECTION_NODE: { |
|
466 break; |
|
467 } |
|
468 case XML_ENTITY_REF_NODE: break; |
|
469 case XML_ENTITY_NODE: break; |
|
470 case XML_PI_NODE: break; |
|
471 case XML_COMMENT_NODE: break; |
|
472 case XML_DOCUMENT_NODE: break; |
|
473 case XML_DOCUMENT_TYPE_NODE: break; |
|
474 case XML_DOCUMENT_FRAG_NODE: break; |
|
475 case XML_NOTATION_NODE: break; |
|
476 case XML_HTML_DOCUMENT_NODE: break; |
|
477 case XML_DTD_NODE: break; |
|
478 case XML_ELEMENT_DECL: break; |
|
479 case XML_ATTRIBUTE_DECL: break; |
|
480 case XML_ENTITY_DECL: break; |
|
481 case XML_NAMESPACE_DECL: break; |
|
482 case XML_XINCLUDE_START: break; |
|
483 case XML_XINCLUDE_END: break; |
|
484 default: break; |
|
485 } |
|
486 return 0; |
|
487 } |
|
488 |
|
489 static int xml_ser_node_end(xmlNode *node, void *userdata) { |
|
490 XmlWriter *xw = userdata; |
|
491 Writer *out = xw->out; |
|
492 if(node->type == XML_ELEMENT_NODE) { |
|
493 if(node->children) { |
|
494 writer_puts(xw->out, S("</")); |
|
495 // write prefix and ':' |
|
496 if(node->ns && node->ns->prefix) { |
|
497 writer_puts(out, sstr((char*)node->ns->prefix)); |
|
498 writer_putc(out, ':'); |
|
499 } |
|
500 // name and close tag |
|
501 writer_puts(out, sstr((char*)node->name)); |
|
502 writer_putc(out, '>'); |
|
503 |
|
504 } // element was already closed in xml_ser_node_begin |
|
505 } |
|
506 return 0; |
|
507 } |
|
508 |
|
509 |
|
510 static int xml_write_nodes( |
|
511 pool_handle_t *pool, |
|
512 Writer *out, |
|
513 UcxMap *nsdefs, |
|
514 WSBool createdefs, |
|
515 xmlNode *node) |
|
516 { |
|
517 XmlWriter xmlwriter; |
|
518 xmlwriter.pool = pool; |
|
519 xmlwriter.out = out; |
|
520 xmlwriter.namespaces = nsdefs; |
|
521 xmlwriter.define_namespaces = createdefs; |
|
522 |
|
523 // iterate over xml nodes |
|
524 // this includes node->children and node->next |
|
525 int err = wsxml_iterator( |
|
526 pool, |
|
527 node, |
|
528 xml_ser_node_begin, |
|
529 xml_ser_node_end, |
|
530 &xmlwriter); |
|
531 if(err) { |
|
532 return -1; |
|
533 } |
|
534 |
|
535 return out->error; |
|
536 } |
|
537 |
|
538 int wsxml_write_nodes( |
|
539 pool_handle_t *pool, |
|
540 Writer *out, |
|
541 UcxMap *nsdefs, |
|
542 xmlNode *node) |
|
543 { |
|
544 return xml_write_nodes(pool, out, nsdefs, TRUE, node); |
|
545 } |
|
546 |
|
547 int wsxml_write_nodes_without_nsdef( |
|
548 pool_handle_t *pool, |
|
549 Writer *out, |
|
550 xmlNode *node) |
|
551 { |
|
552 return xml_write_nodes(pool, out, NULL, FALSE, node); |
|
553 } |