public function _build_xml ($k, $v) {
		if (is_object ($v) && strtolower (get_class ($v)) == 'simplexmlelement') {
			return preg_replace ('/<\?xml(.*?)\?>\n*/', '', $v->asXML ());
		}
		$res = '';
		$attrs = '';
		if (! is_numeric ($k)) {
			$res = '<' . $k . '{{attributes}}>';
		}
		if (is_object ($v)) {
			$v = (array) $v;
		}
		if (is_array ($v)) {
			foreach ($v as $key => $value) {
				// handle attributes of repeating tags
				if (is_numeric ($key) && is_array ($value)) {
					foreach ($value as $sub_key => $sub_value) {
						if (strpos ($sub_key, '@') === 0) {
							$attrs .= ' ' . substr ($sub_key, 1) . '="' . $this->_xml_entities ($sub_value) . '"';
							unset ($value[$sub_key]);
							continue;
						}
					}
				}

				if (strpos ($key, '@') === 0) {
					$attrs .= ' ' . substr ($key, 1) . '="' . $this->_xml_entities ($value) . '"';
					continue;
				}
				$res .= $this->_build_xml ($key, $value);
				$keys = array_keys ($v);
				if (is_numeric ($key) && $key !== array_pop ($keys)) {
					// reset attributes on repeating tags
					if (is_array ($value)) {
						$res = str_replace ('<' . $k . '{{attributes}}>', '<' . $k . $attrs . '>', $res);
						$attrs = '';
					}
					$res .= '</' . $k . ">\n<" . $k . '{{attributes}}>';
				}
			}
		} else {
			$res .= $this->_xml_entities ($v);
		}
		if (! is_numeric ($k)) {
			$res .= '</' . $k . ">\n";
		}
		$res = str_replace ('<' . $k . '{{attributes}}>', '<' . $k . $attrs . '>', $res);
		return $res;
	}