<commit_before># Easy and fast marshalling of XML to Java

DOM parsing tends to make for code that is easy to read and write, but is very slow, memory intensive, and generates heaps of garbage. 

SAX and "pull" parsing can lead to complex code and tortuously nested `if` statements, or lots of boiler-plate code to create state-machines.

Inspired by some recent work speeding up XML parsing in a slow Android application, `dsl4xml` is my free-time thought-experiment with the following aims:

1. To make _readable_ declarative code that marshalls XML documents to Java objects.
2. To make marshalling XML documents to Java objects very fast (pull parsing speeds).
3. To avoid polluting model classes with metadata about xml parsing (no annotations).
4. To avoid additional build-time steps (code generators, etc).

It works by providing a thin DSL wrapper around a Pull-Parser to declaratively construct a state-machine that marshalls XML documents into Java objects. 

The DSL mirrors the structure of the XML document itself, making it very easy to write (and importantly to _read_ and _maintain_) XML marshalling code.

## Examples

Given a simple XML like this:

	<books>
	    <book>
	        <title>The Hobbit</title>
	        <synopsis>A little guy goes on an adventure, finds ring, comes back.</synopsis>
	    </book>
	    <book>
	        <title>The Lord of the Rings</title>
	        <synopsis>A couple of little guys go on an adventure, lose ring, come back.</synopsis>
	    </book>
	</books>

And some simple model objects we want to marshall to that look like this:

    class Books implements Iterable<Book> {
       private List<Book> books = new ArrayList<Book>();
       
       public void addBook(Book aBook) {
           books.add(aBook)l
       }
       
       public Iterator<Book> iterator() {
           return books.iterator();
       }
    }
    
    class Book {
    	private String title;
    	private String synopsis;
    	
    	public String getTitle() {
    	    return title;
    	}
    	
    	public void setTitle(String aTitle) {
    	    title = aTitle;
    	}
    	
    	public String getSynopsis() {
    	    return synopsis;
    	}
    	
    	public void setSynopsis(String aSynopsis) {
    	    synopsis = aSynopsis;
    	}
    }

We can marshall the XML to those model objects using the following simple Java code:

    import static com.sjl.dsl4xml.DocumentMarshaller.*;

    class BooksMarshaller {
	    private DocumentMarshaller<Books> marshaller;

	    public BooksMarshaller() {
	        marshaller = mappingOf(Books.class).to(
		        tag("book", Book.class).with(
	               tag("title").withCData(),
	               tag("synopsis").withCData()
			    )
		    );
	    }

        public Books marshall(Reader aReader) {
            return marshaller.marshall(aReader);
	    }
	}
	
.. more soon ...<commit_msg>balancing the arguments between DOM and SAX/pull parsing<commit_after># Easy and fast marshalling of XML to Java

DOM parsing tends to make for code that is easy to read and write, but is very slow, memory intensive, and generates heaps of garbage. 

SAX and "pull" parsing tend to be very fast, have significantly lower memory requirements, and typically produce much less garbage, but can lead to complex code and tortuously nested `if` statements, or lots of boiler-plate code to create state-machines.

Inspired by some recent work speeding up XML parsing in a slow Android application, `dsl4xml` is my free-time thought-experiment with the following aims:

1. To make _readable_ declarative code that marshalls XML documents to Java objects.
2. To make marshalling XML documents to Java objects very fast (pull parsing speeds).
3. To avoid polluting model classes with metadata about xml parsing (no annotations).
4. To avoid additional build-time steps (code generators, etc).

It works by providing a thin DSL wrapper around a Pull-Parser to declaratively construct a state-machine that marshalls XML documents into Java objects. 

The DSL mirrors the structure of the XML document itself, making it very easy to write (and importantly to _read_ and _maintain_) XML marshalling code.

## Examples

Given a simple XML like this:

	<books>
	    <book>
	        <title>The Hobbit</title>
	        <synopsis>A little guy goes on an adventure, finds ring, comes back.</synopsis>
	    </book>
	    <book>
	        <title>The Lord of the Rings</title>
	        <synopsis>A couple of little guys go on an adventure, lose ring, come back.</synopsis>
	    </book>
	</books>

And some simple model objects we want to marshall to that look like this:

    class Books implements Iterable<Book> {
       private List<Book> books = new ArrayList<Book>();
       
       public void addBook(Book aBook) {
           books.add(aBook)l
       }
       
       public Iterator<Book> iterator() {
           return books.iterator();
       }
    }
    
    class Book {
    	private String title;
    	private String synopsis;
    	
    	public String getTitle() {
    	    return title;
    	}
    	
    	public void setTitle(String aTitle) {
    	    title = aTitle;
    	}
    	
    	public String getSynopsis() {
    	    return synopsis;
    	}
    	
    	public void setSynopsis(String aSynopsis) {
    	    synopsis = aSynopsis;
    	}
    }

We can marshall the XML to those model objects using the following simple Java code:

    import static com.sjl.dsl4xml.DocumentMarshaller.*;

    class BooksMarshaller {
	    private DocumentMarshaller<Books> marshaller;

	    public BooksMarshaller() {
	        marshaller = mappingOf(Books.class).to(
		        tag("book", Book.class).with(
	               tag("title").withCData(),
	               tag("synopsis").withCData()
			    )
		    );
	    }

        public Books marshall(Reader aReader) {
            return marshaller.marshall(aReader);
	    }
	}
	
.. more soon ...
{'fraction_non_alphanumeric': 0.07072424345460727, 'fraction_numerical': 0.002040122407344441, 'mean_word_length': 2.649503722084367, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '713160', 'n_tokens_mistral': 1701, 'n_tokens_neox': 1585, 'n_words': 668}