Giter VIP home page Giter VIP logo

xml.c's Introduction

xml.c

Similar to the GLib Markup parser, which also just parses an xml subset, xml.c is a simple, small and self contained xml parser in one file. Ideal for embedding into other projects without the need for big external dependencies.

Build Status

Downloads

All releases are based on master, so the preferred way of using xml.c is adding the repository as git submodule.

If you prefer formal releases, check out the release tags.

Building xml.c

Since xml.c uses CMake, building the library is fairly easy

$ git clone https://github.com/ooxi/xml.c.git xml.c
$ mkdir xml.c/build; cd xml.c/build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make && make test

If you need a debug build, specify CMAKE_BUILD_TYPE as Debug and rebuild.

Usage

This example is also included in the repository and will be build by default. Most of the code is C boilerplate, the important functions are xml_parse_document, xml_document_root, xml_node_name, xml_node_content and xml_node_child / xml_node_children.

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <xml.h>



int main(int argc, char** argv) {

	/* XML source, could be read from disk
	 */
	uint8_t* source = ""
		"<Root>"
			"<Hello>World</Hello>"
			"<This>"
				"<Is>:-)</Is>"
				"<An>:-O</An>"
				"<Example>:-D</Example>"
			"</This>"
		"</Root>"
	;


	/* Parse the document
	 *
	 * Watch out: Remember not to free the source until you have freed the
	 *     document itself. If you have to free the source before, supply a
	 *     copy to xml_parse_document which can be freed together with the
	 *     document (`free_buffer' argument to `xml_document_free')
	 */
	struct xml_document* document = xml_parse_document(source, strlen(source));

	/* You _have_ to check the result of `xml_parse_document', if it's 0
	 * then the source could not be parsed. If you think this is a bug in
	 * xml.c, then use a debug build (cmake -DCMAKE_BUILD_TYPE=Debug) which
	 * will verbosely tell you about the parsing process
	 */
	if (!document) {
		printf("Could parse document\n");
		exit(EXIT_FAILURE);
	}
	struct xml_node* root = xml_document_root(document);


	/* Say Hello World :-)
	 */
	struct xml_node* root_hello = xml_node_child(root, 0);
	struct xml_string* hello = xml_node_name(root_hello);
	struct xml_string* world = xml_node_content(root_hello);

	/* Watch out: `xml_string_copy' will not 0-terminate your buffers! (but
	 *     `calloc' will :-)
	 */
	uint8_t* hello_0 = calloc(xml_string_length(hello) + 1, sizeof(uint8_t));
	uint8_t* world_0 = calloc(xml_string_length(world) + 1, sizeof(uint8_t));
	xml_string_copy(hello, hello_0, xml_string_length(hello));
	xml_string_copy(world, world_0, xml_string_length(world));

	printf("%s %s\n", hello_0, world_0);
	free(hello_0);
	free(world_0);


	/* Extract amount of Root/This children
	 */
	struct xml_node* root_this = xml_node_child(root, 1);
	printf("Root/This has %lu children\n", (unsigned long)xml_node_children(root_this));


	/* Remember to free the document or you'll risk a memory leak
	 */
	xml_document_free(document, false);
}

Another usage example can be found in the unit case.

License

libpng/zlib (BSD)

xml.c's People

Contributors

devintrowbridge avatar isty001 avatar luksow avatar molorius avatar ooxi avatar sgraham avatar tweakdeveloper avatar yusiwen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xml.c's Issues

use xml_easy_child in for loop ?

Hello i want to use xml_easy in for lopp like this :

        struct xml_node* root = xml_document_root(document);
        size_t const number_of_features_type = xml_node_children(root);
        int i;
        for( i = 0; i < number_of_features_type; i++ ){
            
            struct xml_node* myxml_node = xml_easy_child(root, i, 0);
        }

but i have this error

warning: passing argument 2 of ‘xml_easy_child’ makes pointer from integer without a cast [enabled by default]
note: expected ‘const uint8_t *’ but argument is of type ‘unsigned char’

how "convert" my i variable to const ? or have you other solution ?

Does not handle new lines in tags

Hi, I'm trying to parse an svg, and I'm getting an error:

xml_parser_error at 10:22: xml_parse_node::tag missmatch
xml_parser_error at 11:0 (is  ): xml_parse_node::child
xml_parser_error at 10:22: xml_parse_document::parsing document failed

From reading other issues, I've tried removing the header, removing comments, replacing spaces, and replacing single tags (/>)

Here's the file:

<svg
   width="210mm"
   height="297mm"
   viewBox="0&#032;0&#032;210&#032;297"
   version="1.1"
   id="svg5"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <defs
     id="defs2"></defs>
  <rect
     style="fill:none;stroke:#000000;stroke-width:10;stroke-linejoin:round;paint-order:stroke&#032;fill&#032;markers"
     id="rect896"
     width="100.21762"
     height="58.545967"
     x="30.625204"
     y="89.954025"></rect>
  <rect
     style="fill:#006aff;stroke:#000000;stroke-width:10;stroke-linejoin:round;paint-order:stroke&#032;fill&#032;markers;fill-opacity:1"
     id="rect898"
     width="68.958168"
     height="53.455563"
     x="83.309692"
     y="224.85725"></rect>
</svg>

parse error

xml_parser_error at 175:6 (is 
): xml_parse_tag_open::expected opening tag
xml_parser_error at 175:5: xml_parse_node::tag_open
xml_parser_error at 176:0 (is ): xml_parse_node::child
xml_parser_error at 175:5: xml_parse_document::parsing document failed
Cannot parse file

here's the file

<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="42" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="3" nextobjectid="37">
 <tileset firstgid="1" source="../../ThruStar008/data/tileset.tsx"/>
 <layer id="1" name="Tile Layer 1" width="42" height="25">
  <data encoding="csv">
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,5,5,5,5,5,5,5,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,3,0,0,6,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,6,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,4,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
</data>
 </layer>
 <objectgroup id="2" name="Object Layer 1">
  <object id="1" name="switch1" type="switch" x="192" y="736" width="32" height="32">
   <properties>
    <property name="target" value="door1"/>
   </properties>
  </object>
  <object id="2" name="door1" type="door" x="160" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="4"/>
   </properties>
  </object>
  <object id="4" name="door1" type="door" x="192" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="3"/>
   </properties>
  </object>
  <object id="5" name="door1" type="door" x="224" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="2"/>
   </properties>
  </object>
  <object id="6" name="door1" type="door" x="256" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="1"/>
   </properties>
  </object>
  <object id="7" name="door1" type="door" x="128" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-4"/>
   </properties>
  </object>
  <object id="8" name="door1" type="door" x="96" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-3"/>
   </properties>
  </object>
  <object id="9" name="door1" type="door" x="64" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-2"/>
   </properties>
  </object>
  <object id="10" name="door1" type="door" x="32" y="544" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-1"/>
   </properties>
  </object>
  <object id="11" name="switch2" type="switch" x="992" y="736" width="32" height="32">
   <properties>
    <property name="target" value="door2"/>
   </properties>
  </object>
  <object id="12" name="door2" type="door" x="1056" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-1"/>
   </properties>
  </object>
  <object id="13" name="door2" type="door" x="1152" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-4"/>
   </properties>
  </object>
  <object id="14" name="door2" type="door" x="1120" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-3"/>
   </properties>
  </object>
  <object id="15" name="door2" type="door" x="1088" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-2"/>
   </properties>
  </object>
  <object id="16" name="door2" type="door" x="1184" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="4"/>
   </properties>
  </object>
  <object id="17" name="door2" type="door" x="1248" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="2"/>
   </properties>
  </object>
  <object id="18" name="door2" type="door" x="1280" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="1"/>
   </properties>
  </object>
  <object id="19" name="door2" type="door" x="1216" y="480" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="3"/>
   </properties>
  </object>
  <object id="20" name="door3" type="door" x="608" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-1"/>
   </properties>
  </object>
  <object id="21" name="door3" type="door" x="704" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-4"/>
   </properties>
  </object>
  <object id="22" name="door3" type="door" x="672" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-3"/>
   </properties>
  </object>
  <object id="23" name="door3" type="door" x="640" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="-2"/>
   </properties>
  </object>
  <object id="24" name="door3" type="door" x="736" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="4"/>
   </properties>
  </object>
  <object id="25" name="door3" type="door" x="800" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="2"/>
   </properties>
  </object>
  <object id="26" name="door3" type="door" x="832" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="1"/>
   </properties>
  </object>
  <object id="27" name="door3" type="door" x="768" y="256" width="32" height="32">
   <properties>
    <property name="openOffset" type="float" value="3"/>
   </properties>
  </object>
  <object id="28" name="switch3" type="switch" x="672" y="448" width="32" height="32">
   <properties>
    <property name="target" value="door3"/>
   </properties>
  </object>
  <object id="29" name="exit1" type="exit" x="1088" y="224" width="32" height="32">
   <properties>
    <property name="target" value="level2.tmx"/>
   </properties>
  </object>
 </objectgroup>
</map>

easier text printing

by accessing the string structs (defining the whole struct in end user code)

struct xml_string {
	uint8_t const* buffer;
	size_t length;
};

the end user can then print a string like so....

struct xml_string* anc = xml_node_attribute_content(tchild, k);
printf("%*.*s ", 0, (int)anc->length, (char*)anc->buffer);

I think this would make the examples easier to follow...

Parsing error with xml header and empty element

Hi,

I'm a french embedded developper (sorry for my english mistakes)
I receive data from a distant system, but i can parse it.
There is two errors:
XML header:
<?xml version="1.0" encoding="utf-8" standalone="no" ?>

Empty element:
<vehicleJourney/> there is no space before />

How can i solve these two errors ?
Thanks
Best regards !

Possible memory leak

In xml.c , function xml_easy_child()

lien 835-837:

} else {
  return 0;
}

It should be:

} else {
  va_end(arguments);
  return 0;
}

And line 843 - 845:

if (!next) {
  return 0;
}

It should be:

if (!next) {
  va_end(arguments);
  return 0;
}

Redurce verbosity of debug build

Currently the output is too much, it should only print parser details if requested at compile time (e.g. via -DXML_PARSER_VERBOSE)

Mising CDATA support.

A small XMl-Parse very usefull for µC Apllication, but I missing CDATA support example:

Does not handle processing instructions

Next to not handling comments it also does not recognize processing instructions.

An easy way to overcome this is to use a do while loop in the node parsing like so:
//Need a do while loop to find a proper top tag and allow skipping of processing instructions or comments
do
{
/* Parse open tag
*/
tag_open = xml_parse_tag_open(parser);

if (!tag_open)
{
  xml_parser_error(parser, NO_CHARACTER, "xml_parse_node::tag_open");
  goto exit_failure;
}

original_length = tag_open->length;
attributes = xml_find_attributes(parser, tag_open);

//Check if the tag is a processing instruction or a comment
if((tag_open->length > 0) && ('?' == tag_open->buffer[0]) || (('!' == tag_open->buffer[0]) && ('-' == tag_open->buffer[1]) && ('-' == tag_open->buffer[2])))
{
  //Drop the found processing instruction or comment
  xml_string_free(tag_open);

  //Reset the tag_open pointer to force scanning for the next one
  tag_open = 0;
  
  if(attributes)
  {
    //Need to free attributes!!!!!! also in error handling!!!!! 
  }
}

} while(!tag_open);

Another issue is the freeing of the attributes.

Failure to parse xml attributes in tags

It looks like ooxi/xml.c is unable to parse attributes in tags. It fails with "xml_parser_error at 50:25: xml_parse_node::tag missmatch" and it is because it assumes that the value of tag_open = tag_close without stripping out the attributes before comparing.

unsigned expression < 0 is always false

src/xml.c: In function 'xml_parser_error':
src/xml.c:318:24: error: comparison of unsigned expression < 0 is always false [-Werror=type-limits]
318 | #define max(X,Y) ((X) > (Y) ? (X) : (Y))
| ^
src/xml.c:319:21: note: in expansion of macro 'max'
319 | size_t character = max(0, min(parser->length, parser->position + offset));
|

search a value in my xml file ?

Hello, i use your library for readxml file.
But i have a problem, i want to search a value by node name like this code :

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "./xml.h"


int main(int argc, char** argv) {

	/* XML source, could be read from disk
	 */
	uint8_t* source = ""
		"<Root>"
			"<Hello>World</Hello>"
            
            
            "<Functions>"
            
            "<Function>"
            "<as>testas</as>"
            "<os>testos</os>"
            "</Function>"
            
            "<Function>"
            "<is>testis</is>"
            "<us>testus</us>"
            "<ls>testls</ls>"
            "</Function>"
            
            "<Function>"
            "<mn>testmn</mn>"
            "</Function>"
            
            "</Functions>"
           
		"</Root>"
	;
    
	struct xml_document* document = xml_parse_document(source, strlen(source));

	if (!document) {
		printf("Could parse document\n");
		exit(EXIT_FAILURE);
	}
	struct xml_node* root = xml_document_root(document);

	struct xml_node* root_hello = xml_node_child(root, 0);
	struct xml_string* hello = xml_node_name(root_hello);
	struct xml_string* world = xml_node_content(root_hello);

	uint8_t* hello_0 = calloc(xml_string_length(hello) + 1, sizeof(uint8_t));
	uint8_t* world_0 = calloc(xml_string_length(world) + 1, sizeof(uint8_t));
	xml_string_copy(hello, hello_0, xml_string_length(hello));
	xml_string_copy(world, world_0, xml_string_length(world));
    
    

	printf("%s %s\n", hello_0, world_0);
	free(hello_0);
	free(world_0);

    
    struct xml_node* root_this = xml_easy_child(root, "Functions",0);
    
    
    unsigned long number_of_function=(unsigned long)xml_node_children(root_this);
	printf("Root/This has %lu children\n", number_of_function);
    
    int i=0;
    
    // i want to search value of node "us" for example
    for (i=0;i<number_of_function;i++) {
        printf("%i \n ",i);
        
        struct xml_node* TMP_function_node = xml_easy_child(root, "Functions", 0, i);
        struct xml_string* TMP_function = xml_node_content(TMP_function_node);
        uint8_t* TMP_function_0 = calloc(xml_string_length(TMP_function) + 1, sizeof(uint8_t));
        xml_string_copy(TMP_function, TMP_function_0, xml_string_length(TMP_function));
        printf("%s\n", TMP_function_0);
    }

	xml_document_free(document, false);
}

in this code, i want to get value of my node "us" for example, in root/Functions/function/us
but how can i make this, because i have many Function node.

thanks for advance for your help

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.