static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot) {
    if (!skipRoot) {
        const char* elem = dom.getName(node);
        if (dom.getType(node) == SkDOM::kText_Type) {
            SkASSERT(dom.countChildren(node) == 0);
            w->addText(elem, strlen(elem));
            return;
        }

        w->startElement(elem);

        SkDOM::AttrIter iter(dom, node);
        const char* name;
        const char* value;
        while ((name = iter.next(&value)) != nullptr) {
            w->addAttribute(name, value);
        }
    }

    node = dom.getFirstChild(node, nullptr);
    while (node) {
        write_dom(dom, node, w, false);
        node = dom.getNextSibling(node, nullptr);
    }

    if (!skipRoot) {
        w->endElement();
    }
}
SkXMLListSource::SkXMLListSource(const char doc[], size_t len)
{
	fFieldCount = fRecordCount = 0;
	fFields = fRecords = NULL;

	SkDOM	dom;

	const SkDOM::Node* node = dom.build(doc, len);
	SkASSERT(node);
	const SkDOM::Node*	child;	

	child = dom.getFirstChild(node, "fields");
	if (child)
	{
		fFieldCount = dom.countChildren(child, "field");
		fFields = new SkString[fFieldCount];

		int n = 0;
		child = dom.getFirstChild(child, "field");
		while (child)
		{
			fFields[n].set(dom.findAttr(child, "name"));
			child = dom.getNextSibling(child, "field");
			n += 1;
		}
		SkASSERT(n == fFieldCount);
	}
	
	child = dom.getFirstChild(node, "records");
	if (child)
	{
		fRecordCount = dom.countChildren(child, "record");
		fRecords = new SkString[fRecordCount * fFieldCount];

		int n = 0;
		child = dom.getFirstChild(child, "record");
		while (child)
		{
			for (int i = 0; i < fFieldCount; i++)
				fRecords[n * fFieldCount + i].set(dom.findAttr(child, fFields[i].c_str()));
			child = dom.getNextSibling(child, "record");
			n += 1;
		}
		SkASSERT(n == fRecordCount);
	}
}
void SkListView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
{
	this->INHERITED::onInflate(dom, node);
	
	{
		bool hasScrollBar;
		if (dom.findBool(node, "scrollBar", &hasScrollBar))
			this->setHasScrollBar(hasScrollBar);
	}

	const SkDOM::Node*	child;

	if ((child = dom.getFirstChild(node, "bindings")) != NULL)
	{
		delete[] fBindings;
		fBindings = NULL;
		fBindingCount = 0;

		SkListSource* listSrc = SkListSource::Factory(dom.findAttr(child, "data-fields"));
		SkASSERT(listSrc);
		fSkinName.set(dom.findAttr(child, "skin-slots"));
		SkASSERT(fSkinName.size());

		this->setListSource(listSrc)->unref();
			
		int count = dom.countChildren(child, "bind");
		if (count > 0)
		{
			fBindings = new BindingRec[count];
			count = 0;	// reuse this to count up to the number of valid bindings

			child = dom.getFirstChild(child, "bind");
			SkASSERT(child);
			do {
				const char* fieldName = dom.findAttr(child, "field");
				const char* slotName = dom.findAttr(child, "slot");
				if (fieldName && slotName)
				{
					fBindings[count].fFieldIndex = listSrc->findFieldIndex(fieldName);
					if (fBindings[count].fFieldIndex >= 0)
						fBindings[count++].fSlotName.set(slotName);
				}
			} while ((child = dom.getNextSibling(child, "bind")) != NULL);

			fBindingCount = SkToU16(count);
			if (count == 0)
			{
				SkDEBUGF(("SkListView::onInflate: no valid <bind> elements in <listsource>\n"));
				delete[] fBindings;
			}
		}
		this->dirtyCache(kAnimCount_DirtyFlag);
		this->setSelection(0);
	}
}