Mercurial Hosting > luan
changeset 1468:35f3bfd4f51d
xml
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 14 Apr 2020 08:44:33 -0600 |
parents | 509d49c493c0 |
children | 21f5edab1fbf |
files | src/goodjava/xml/XmlElement.java src/goodjava/xml/XmlParser.java src/luan/modules/parsers/Xml.java |
diffstat | 3 files changed, 126 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/src/goodjava/xml/XmlElement.java Mon Apr 13 22:16:59 2020 -0600 +++ b/src/goodjava/xml/XmlElement.java Tue Apr 14 08:44:33 2020 -0600 @@ -8,13 +8,25 @@ public final Map<String,String> attributes; public final Object content; + public XmlElement(String name,Map<String,String> attributes) { + this.name = name; + this.attributes = attributes; + this.content = null; + } + public XmlElement(String name,Map<String,String> attributes,String content) { + if( content == null ) + throw new IllegalArgumentException("content can't be null"); this.name = name; this.attributes = attributes; this.content = content; } public XmlElement(String name,Map<String,String> attributes,XmlElement[] content) { + if( content == null ) + throw new IllegalArgumentException("content can't be null"); + if( content.length == 0 ) + throw new IllegalArgumentException("content can't be empty"); this.name = name; this.attributes = attributes; this.content = content; @@ -34,21 +46,29 @@ sb.append( ' ' ); sb.append( attribute.getKey() ); sb.append( "=\"" ); - sb.append( attribute.getValue() ); + sb.append( encode(attribute.getValue()) ); sb.append( '"' ); } - sb.append( '>' ); - if( content instanceof String ) { + if( content == null ) { + sb.append( "/>\n" ); + } else if( content instanceof String ) { + sb.append( '>' ); String s = (String)content; - sb.append(s); + sb.append( encode(s) ); + closeTag(sb,name); } else { + sb.append( '>' ); XmlElement[] elements = (XmlElement[])content; sb.append( '\n' ); for( XmlElement element : elements ) { element.toString(sb,indented+1); } indent(sb,indented); + closeTag(sb,name); } + } + + private static void closeTag(StringBuilder sb,String name) { sb.append( "</" ); sb.append( name ); sb.append( ">\n" ); @@ -60,4 +80,29 @@ } } + private static String encode(String s) { + final char[] a = s.toCharArray(); + StringBuilder buf = new StringBuilder(); + for( int i=0; i<a.length; i++ ) { + char c = a[i]; + switch(c) { + case '&': + buf.append("&"); + break; + case '<': + buf.append("<"); + break; + case '>': + buf.append(">"); + break; + case '"': + buf.append("""); + break; + default: + buf.append(c); + } + } + return buf.toString(); + } + }
--- a/src/goodjava/xml/XmlParser.java Mon Apr 13 22:16:59 2020 -0600 +++ b/src/goodjava/xml/XmlParser.java Tue Apr 14 08:44:33 2020 -0600 @@ -58,6 +58,10 @@ attributes.put(attribute.getKey(),attribute.getValue()); } spaces(); + if( parser.match("/>") ) { + XmlElement element = new XmlElement(name,attributes); + return parser.success(element); + } required(">"); String s = string(name); if( s != null ) { @@ -76,6 +80,7 @@ int start = parser.begin(); while( parser.noneOf("<") ); String s = parser.textFrom(start); + s = decode(s); if( !endTag(name) ) return parser.failure(null); return parser.success(s); @@ -125,6 +130,7 @@ throw exception("unclosed attribute value"); } String value = parser.textFrom(start); + value = decode(value); parser.match(quote); Map.Entry<String,String> attribute = new AbstractMap.SimpleImmutableEntry<String,String>(name,value); return parser.success(attribute); @@ -169,4 +175,13 @@ return parser.anyOf(" \t\r\n"); } + private static String decode(String s) { + s = s.replace("<","<"); + s = s.replace(">",">"); + s = s.replace(""","\""); + s = s.replace("'","'"); + s = s.replace("&","&"); + return s; + } + }
--- a/src/luan/modules/parsers/Xml.java Mon Apr 13 22:16:59 2020 -0600 +++ b/src/luan/modules/parsers/Xml.java Tue Apr 14 08:44:33 2020 -0600 @@ -16,24 +16,48 @@ public final class Xml { public static String toString(LuanTable tbl) throws LuanException { - if( tbl.rawSize() != 1 ) - throw new LuanException("XML most have 1 root element"); - Map.Entry entry = tbl.iterator().next(); - Object key = entry.getKey(); - if( !(key instanceof String) ) - throw new LuanException("XML key must be string"); - String name = (String)key; - Object value = entry.getValue(); - if( !(value instanceof LuanTable) ) - throw new LuanException("XML root value must be table"); - LuanTable t = (LuanTable)value; - Map<String,String> attributes = attributes(t); - XmlElement[] elements = elements(t); - XmlElement element = new XmlElement(name,attributes,elements); - return element.toString(); + 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 = new Integer(1); + private static final Integer ONE = Integer.valueOf(1); + private static final Integer TWO = Integer.valueOf(2); + + 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(); + XmlElement element; + if( value instanceof String ) { + String s = (String)value; + element = new XmlElement(name,Collections.emptyMap(),s); + } else { + LuanTable t = (LuanTable)value; + Map<String,String> attributes = attributes(t); + String s = (String)t.get(TWO); + if( s != null ) { + element = new XmlElement(name,attributes,s); + } else { + XmlElement[] elements = elements(t); + if( elements.length==0 ) { + element = new XmlElement(name,attributes); + } else { + element = new XmlElement(name,attributes,elements); + } + } + } + list.add(element); + } + return list.toArray(new XmlElement[0]); + } private static Map<String,String> attributes(LuanTable tbl) throws LuanException { Object obj = tbl.get(ONE); @@ -49,43 +73,36 @@ return map; } - 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; - String name = (String)key; - Object value = entry.getValue(); - XmlElement element; - if( value instanceof String ) { - String s = (String)value; - element = new XmlElement(name,Collections.emptyMap(),s); - } else { - LuanTable t = (LuanTable)value; - Map<String,String> attributes = attributes(t); - XmlElement[] elements = elements(t); - element = new XmlElement(name,attributes,elements); - } - list.add(element); - } - return list.toArray(new XmlElement[0]); - } - public static LuanTable parse(Luan luan,String s) throws ParseException, LuanException { XmlElement element = XmlParser.parse(s); - return toTable(luan,new XmlElement[]{element}); + LuanTable tbl = new LuanTable(luan); + addElements(tbl,new XmlElement[]{element}); + return tbl; } - private static LuanTable toTable(Luan luan,XmlElement[] elements) throws LuanException { - LuanTable tbl = new LuanTable(luan); + private static LuanTable addElements(LuanTable tbl,XmlElement[] elements) throws LuanException { for( XmlElement element : elements ) { - if( element.content instanceof String ) { - tbl.put(element.name,element.content); + 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 ); + } + if( element.content == null ) { + tbl.put(element.name,t); + } else if( element.content instanceof String ) { + if( t.isEmpty() ) { + tbl.put(element.name,element.content); + } else { + t.put( 2, element.content ); + tbl.put(element.name,t); + } } else { XmlElement[] els = (XmlElement[])element.content; - LuanTable t = toTable(luan,els); + addElements(t,els); tbl.put(element.name,t); } }