The page data is converted into a linked list. The linked list is then processed by a visitor to get displayed.

The reason the visitor pattern is used is to allow future versions to replace the dump data dump visitor with something a bit more performant, say an on demand code generator.

Technically a SAX parser would yield better performance when processing the initial XML document than a DOM parser. However, developing SAX parser code is more complicated than just manipulating a DOM tree. Also this is done only once.

Attributes

Although other similar frameworks use only one attribute to perform their tasks. We use multiple in order to keep things cleaner.

component
specifies a component to use, the default would be Property
property
specifies a page bean property to use.
href
specifies a file to include into the document

Pre-processing sequence

These events happen in sequence after the initial document has been loaded.

  1. Find all elements that have component="$remove" and remove them from the tree.
  2. while there exists comonent="$include" elements.
    1. Find all elements that have component="$include" and replace with the included file.
    2. Find all elements that have component="$remove" and remove them from the tree.

Processing sequence

After the document has been preprocessed, it goes through the SAX parser.

startElement() {
	if element has component {
		pageData.add(new StringPageData(buffer));
		ComponentPageDataBuilder builder = new ComponentPageDataBuilder();
		ComponentPageData c = builder.buildComponentPageData(element);	
		componentPageDataStack.push(c);
	} else {
		++plainStack;
		buffer.append(element);
	}
}
endElement() {
	if (plainStack > 0) { // isStillPlainComponent
		buffer.append(element);
		--plainStack;
	} else {
		ComponentPageData c = componentPageDataStack.top();
		componentPageDataStack.pop();
		if (componentPageDataStack.isEmpty()) {
			pageData.add(c);
		} else {
			ComponentPageData parent = componentPageDataStack.top();
			parent.add(c);
		}
	}
}
startElement() {
	if element has component {
		pageData.add(new StringPageData(buffer));
		ComponentPageDataBuilder builder = new ComponentPageDataBuilder();
		ComponentPageData c = builder.buildComponentPageData(element);	
		componentPageDataStack.push(c);
	} else {
		++plainStack;
		buffer.append(element);
	}
}
endElement() {
	if (plainStack > 0) { // isStillPlainComponent
		buffer.append(element);
		--plainStack;
	} else {
		ComponentPageData c = componentPageDataStack.top();
		componentPageDataStack.pop();
		if (componentPageDataStack.isEmpty()) {
			pageData.add(c);
		} else {
			ComponentPageData parent = componentPageDataStack.top();
			parent.add(c);
		}
	}
}