changeset 1791:f8f5c51f5b36

xml work
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 26 Dec 2023 19:16:18 -0700
parents a8c685a894b4
children a5f62fe28b3e
files src/goodjava/xml/XmlElement.java src/luan/modules/Parsers.luan src/luan/modules/Xml.luan src/luan/modules/parsers/LuanToString.java src/luan/modules/parsers/Xml2.java
diffstat 5 files changed, 109 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/src/goodjava/xml/XmlElement.java	Mon Dec 25 23:07:59 2023 -0700
+++ b/src/goodjava/xml/XmlElement.java	Tue Dec 26 19:16:18 2023 -0700
@@ -7,6 +7,7 @@
 	public final String name;
 	public final Map<String,String> attributes;
 	private Object content = null;
+	private XmlElement parent = null;
 
 	public XmlElement(String name,Map<String,String> attributes) {
 		this.name = name;
@@ -14,6 +15,10 @@
 		this.content = null;
 	}
 
+	public XmlElement getParent() {
+		return parent;
+	}
+
 	public Object getContent() {
 		return content;
 	}
@@ -34,6 +39,9 @@
 		if( content.length == 0 )
 			throw new IllegalArgumentException("content can't be empty");
 		this.content = content;
+		for( XmlElement el : content ) {
+			el.parent = this;
+		}
 	}
 
 	@Override public String toString() {
--- a/src/luan/modules/Parsers.luan	Mon Dec 25 23:07:59 2023 -0700
+++ b/src/luan/modules/Parsers.luan	Tue Dec 26 19:16:18 2023 -0700
@@ -4,6 +4,7 @@
 local Csv = require "java:luan.modules.parsers.Csv"
 local Theme = require "java:luan.modules.parsers.Theme"
 local Xml = require "java:luan.modules.parsers.Xml"
+local Xml2 = require "java:luan.modules.parsers.Xml2"
 local XmlElement = require "java:goodjava.xml.XmlElement"
 local BasicLuan = require "java:luan.modules.BasicLuan"
 
@@ -18,6 +19,8 @@
 Parsers.xml_encode = XmlElement.encode
 Parsers.xml_parse = Xml.parse
 Parsers.xml_string = Xml.toString
+Parsers.xml2_parse = Xml2.parse
+Parsers.xml2_string = Xml2.toString
 
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
--- a/src/luan/modules/Xml.luan	Mon Dec 25 23:07:59 2023 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-require "java"
-local XmlParser = require "java:goodjava.xml.XmlParser"
-local XmlElement = require "java:goodjava.xml.XmlElement"
-local Luan = require "luan:Luan.luan"
-local error = Luan.error
-local set_metatable = Luan.set_metatable or error()
-
-
-local Xml = {}
-
-Xml.encode = XmlElement.encode
-
-local function new(java,mt)
-	local t = {}
-	t.java = java
-	set_metatable(t,mt)
-	return t
-end
-
-local element_mt = {}
-
-local xml_mt = {}
-function xml_mt.__index(xml,key)
-	if key == "element" then
-		return new( xml.java.element, element_mt )
-	end
-	if key == "declaration" then
-		return xml.java.declaration
-	end
-	return nil
-end
-function xml_mt.__new_index(xml,key,value)
-	if key == "element" then
-		xml.java.setElement( value.java )
-	elseif key == "declaration" then
-		xml.java.declaration = value
-	else
-		error("invalid key: "..key)
-	end
-end
-function xml_mt.__to_string(xml)
-	return xml.java.toString()
-end
-
-function Xml.parse(text)
-	return new( XmlParser.parse(text), xml_mt )
-end
-
-return Xml
--- a/src/luan/modules/parsers/LuanToString.java	Mon Dec 25 23:07:59 2023 -0700
+++ b/src/luan/modules/parsers/LuanToString.java	Tue Dec 26 19:16:18 2023 -0700
@@ -79,6 +79,7 @@
 	private final Luan luan;
 	private final LuanFunction fnOptions;
 	private final LuanTable stack = new LuanTable();
+	private final Set<LuanTable> seen = new HashSet<LuanTable>();
 
 	public LuanToString() {
 		this.luan = null;
@@ -115,11 +116,11 @@
 
 	public String toString(Object obj) throws LuanException {
 		StringBuilder sb = new StringBuilder();
-		toString(obj,sb,0,settingsInit);
+		objectToString(obj,sb,0,settingsInit);
 		return sb.toString();
 	}
 
-	private void toString(Object obj,StringBuilder sb,int indented,Settings settings) throws LuanException {
+	private void objectToString(Object obj,StringBuilder sb,int indented,Settings settings) throws LuanException {
 		if( obj == null ) {
 			sb.append( "nil" );
 			return;
@@ -148,6 +149,12 @@
 	}
 
 	private void toString(LuanTable tbl,StringBuilder sb,int indented,Settings settings) throws LuanException {
+		if( !seen.add(tbl) ) {
+			if( settings.strict )
+				throw new LuanException("loop in "+tbl.rawToString());
+			sb.append("<loop>");
+			return;
+		}
 		if( tbl.getMetatable()!=null ) {
 			if( settings.strict )
 				throw new LuanException("can't handle metatables when strict");
@@ -207,7 +214,7 @@
 			} else {
 				indent(sb,indented+1);
 			}
-			toString(obj,sb,indented+1,settings);
+			objectToString(obj,sb,indented+1,settings);
 		}
 		for( Object obj : map.entrySet() ) {
 			Map.Entry entry = (Map.Entry)obj;
@@ -247,7 +254,7 @@
 			sb.append( (String)key );
 		} else {
 			sb.append( '[' );
-			toString( key, sb, indented, keySettings );
+			objectToString( key, sb, indented, keySettings );
 			sb.append( ']' );
 		}
 		sb.append( settings.compressed ? "=" : " = " );
@@ -257,7 +264,7 @@
 			settings = settings.cloneSettings();
 			settings.applyOptions(options);
 		}
-		toString( entry.getValue(), sb, indented, settings );
+		objectToString( entry.getValue(), sb, indented, settings );
 		stack.removeFromList(stack.rawLength());  // pop
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/parsers/Xml2.java	Tue Dec 26 19:16:18 2023 -0700
@@ -0,0 +1,86 @@
+package luan.modules.parsers;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import goodjava.parser.ParseException;
+import goodjava.xml.XmlParser;
+import goodjava.xml.Xml;
+import goodjava.xml.XmlElement;
+import luan.LuanTable;
+import luan.LuanException;
+
+
+public final class Xml2 {
+
+	public static LuanTable parse(String s) throws ParseException, LuanException {
+		Xml xml = XmlParser.parse(s);
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut( "declaration", xml.declaration );
+		tbl.rawPut( "element", newElement(xml.getElement()) );
+		return tbl;
+	}
+
+	private static LuanTable newElement(XmlElement element) throws LuanException {
+		LuanTable tbl = new LuanTable();
+		tbl.rawPut( "name", element.name );
+		LuanTable attrs = new LuanTable();
+		for( Map.Entry<String,String> entry : element.attributes.entrySet() ) {
+			attrs.rawPut(entry.getKey(),entry.getValue());
+		}
+		tbl.rawPut( "attributes", attrs );
+		Object content = element.getContent();
+		if( content == null ) {
+			// nothing
+		} else if( content instanceof String ) {
+			tbl.rawPut( "content", content );
+		} else {
+			XmlElement[] elements = (XmlElement[])content;
+			LuanTable t = new LuanTable();
+			for( XmlElement el : elements ) {
+				LuanTable elTbl = newElement(el);
+				elTbl.rawPut( "parent", tbl );
+				t.rawAdd(elTbl);
+			}
+			tbl.rawPut( "content", t );
+		}
+		return tbl;
+	}
+
+
+	public static String toString(LuanTable tbl) {
+		Xml xml = new Xml();
+		xml.declaration = (String)tbl.rawGet("declaration");
+		xml.setElement( element( (LuanTable)tbl.rawGet("element") ) );
+		return xml.toString();
+	}
+
+	private static XmlElement element(LuanTable tbl) {
+		String name = (String)tbl.rawGet("name");
+		Map<String,String> map = new LinkedHashMap<String,String>();
+		{
+			LuanTable t = (LuanTable)tbl.rawGet("attributes");
+			for( Map.Entry entry : t.rawIterable() ) {
+				String key =(String)entry.getKey();
+				String value =(String)entry.getValue();
+				map.put(key,value);
+			}
+		}
+		XmlElement element = new XmlElement(name,map);
+		Object content = tbl.rawGet("content");
+		if( content == null ) {
+			// nothing
+		} else if( content instanceof String ) {
+			element.setContent((String)content);
+		} else if( content instanceof LuanTable ) {
+			LuanTable t = (LuanTable)content;
+			int n = t.rawLength();
+			XmlElement[] a = new XmlElement[n];
+			for( int i=0; i<n; i++ ) {
+				LuanTable elTbl = (LuanTable)t.rawGet(Integer.valueOf(i+1));
+				a[i] = element(elTbl);
+			}
+			element.setContent(a);
+		}
+		return element;
+	}
+}