view src/luan/modules/parsers/Xml.java @ 1471:f5b8c7e1ac82

xml
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 14 Apr 2020 20:20:45 -0600
parents 35f3bfd4f51d
children 2e8a5df45d56
line wrap: on
line source

package luan.modules.parsers;

import java.util.Collections;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ArrayList;
import goodjava.parser.ParseException;
import goodjava.xml.XmlElement;
import goodjava.xml.XmlParser;
import luan.Luan;
import luan.LuanTable;
import luan.LuanException;


public final class Xml {

	public static String toString(LuanTable tbl) throws LuanException {
		XmlElement[] elements = elements(tbl);
		if( elements.length != 1 )
			throw new LuanException("XML must have 1 root element");
		return elements[0].toString();
	}

	private static final Integer ONE = Integer.valueOf(1);
	private static final Integer TWO = Integer.valueOf(2);
	private static final String LIST = "$list";

	private static XmlElement[] elements(LuanTable tbl) throws LuanException {
		List<XmlElement> list = new ArrayList<XmlElement>();
		for( Map.Entry entry : tbl.iterable() ) {
			Object key = entry.getKey();
			if( key.equals(ONE) )
				continue;
			if( !(key instanceof String) )
				throw new LuanException("XML key must be string");
			String name = (String)key;
			Object value = entry.getValue();
			if( value instanceof String ) {
				list.add( element(name,value) );
			} else {
				LuanTable t = (LuanTable)value;
				LuanTable tList = (LuanTable)t.get(LIST);
				if( tList == null ) {
					list.add( element(name,t) );
				} else {
					for( Object obj : tList.asList() ) {
						list.add( element(name,obj) );
					}
				}
			}
		}
		return list.toArray(new XmlElement[0]);
	}

	private static XmlElement element(String name,Object obj) throws LuanException {
		if( obj instanceof String ) {
			return new XmlElement( name, Collections.emptyMap(), (String)obj );
		}
		LuanTable t = (LuanTable)obj;
		Map<String,String> attributes = attributes(t);
		String s = (String)t.get(TWO);
		if( s != null ) {
			return new XmlElement(name,attributes,s);
		} else {
			XmlElement[] elements = elements(t);
			if( elements.length==0 ) {
				return new XmlElement(name,attributes);
			} else {
				return new XmlElement(name,attributes,elements);
			}
		}
	}

	private static Map<String,String> attributes(LuanTable tbl) throws LuanException {
		Object obj = tbl.get(ONE);
		if( obj==null )
			return Collections.emptyMap();
		LuanTable t = (LuanTable)obj;
		Map<String,String> map = new LinkedHashMap<String,String>();
		for( Map.Entry entry : t.iterable() ) {
			String name =(String)entry.getKey();
			String value =(String)entry.getValue();
			map.put(name,value);
		}
		return map;
	}


	public static LuanTable parse(Luan luan,String s) throws ParseException, LuanException {
		XmlElement element = XmlParser.parse(s);
		LuanTable tbl = new LuanTable(luan);
		addElements(tbl,new XmlElement[]{element});
		return tbl;
	}

	private static LuanTable addElements(LuanTable tbl,XmlElement[] elements) throws LuanException {
		for( XmlElement element : elements ) {
			LuanTable t = new LuanTable(tbl.luan());
			if( !element.attributes.isEmpty() ) {
				LuanTable attrs = new LuanTable(tbl.luan());
				for( Map.Entry<String,String> entry : element.attributes.entrySet() ) {
					attrs.put(entry.getKey(),entry.getValue());
				}
				t.put( 1, attrs );
			}
			Object value = t;
			if( element.content == null ) {
				// nothing
			} else if( element.content instanceof String ) {
				if( t.isEmpty() ) {
					value = element.content;
				} else {
					t.put( 2, element.content );
				}
			} else {
				XmlElement[] els = (XmlElement[])element.content;
				addElements(t,els);
			}
			Object old = tbl.get(element.name);
			if( old==null ) {
				tbl.put(element.name,value);
			} else {
				LuanTable list = null;
				if( old instanceof LuanTable )
					list = (LuanTable)((LuanTable)old).get(LIST);
				if( list==null ) {
					list = new LuanTable(tbl.luan());
					list.rawAdd(old);
					LuanTable wrap = new LuanTable(tbl.luan());
					wrap.put(LIST,list);
					tbl.put(element.name,wrap);
				}
				list.rawAdd(value);
			}
		}
		return tbl;
	}

}