Mercurial Hosting > luan
comparison src/luan/modules/HtmlLuan.java @ 775:1a68fc55a80c
simplify dir structure
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 26 Aug 2016 14:36:40 -0600 |
parents | core/src/luan/modules/HtmlLuan.java@cdc70de628b5 |
children | 25746915a241 |
comparison
equal
deleted
inserted
replaced
774:3e30cf310e56 | 775:1a68fc55a80c |
---|---|
1 package luan.modules; | |
2 | |
3 import java.util.List; | |
4 import java.util.ArrayList; | |
5 import java.util.Arrays; | |
6 import java.util.Set; | |
7 import java.util.HashSet; | |
8 import java.util.Map; | |
9 import luan.Luan; | |
10 import luan.LuanState; | |
11 import luan.LuanTable; | |
12 import luan.LuanException; | |
13 | |
14 | |
15 public final class HtmlLuan { | |
16 | |
17 public static String encode(String s) throws LuanException { | |
18 Utils.checkNotNull(s); | |
19 char[] a = s.toCharArray(); | |
20 StringBuilder buf = new StringBuilder(); | |
21 for( int i=0; i<a.length; i++ ) { | |
22 char c = a[i]; | |
23 switch(c) { | |
24 case '&': | |
25 buf.append("&"); | |
26 break; | |
27 case '<': | |
28 buf.append("<"); | |
29 break; | |
30 case '>': | |
31 buf.append(">"); | |
32 break; | |
33 case '"': | |
34 buf.append("""); | |
35 break; | |
36 default: | |
37 buf.append(c); | |
38 } | |
39 } | |
40 return buf.toString(); | |
41 } | |
42 | |
43 /* | |
44 // public static final String TEXTAREA = "textarea"; | |
45 public static final String SCRIPT = "script"; | |
46 public static final String STYLE = "style"; | |
47 | |
48 public static Set<String> containerTags = new HashSet<String>(Arrays.asList(SCRIPT,STYLE)); | |
49 */ | |
50 /* | |
51 public static LuanTable parse(LuanState luan,String text,LuanTable containerTagsTbl) | |
52 throws LuanException | |
53 { | |
54 Utils.checkNotNull(luan,text); | |
55 Utils.checkNotNull(luan,containerTagsTbl); | |
56 Set<String> containerTags = new HashSet<String>(); | |
57 for( Object v : containerTagsTbl.asList() ) { | |
58 containerTags.add((String)v); | |
59 } | |
60 List<Object> html = new ArrayList<Object>(); | |
61 int len = text.length(); | |
62 int i = 0; | |
63 outer: | |
64 while( i < len ) { | |
65 int i2 = text.indexOf('<',i); | |
66 while( i2 != -1 && i2+1 < len ) { | |
67 char c = text.charAt(i2+1); | |
68 if( Character.isLetter(c) || c=='/' || c=='!' ) | |
69 break; | |
70 i2 = text.indexOf('<',i2+1); | |
71 } | |
72 if( i2 == -1 ) { | |
73 html.add( text.substring(i) ); | |
74 break; | |
75 } | |
76 if( i < i2 ) | |
77 html.add( text.substring(i,i2) ); | |
78 if( text.startsWith("<!--",i2) ) { | |
79 i = text.indexOf("-->",i2+4); | |
80 if( i == -1 ) { | |
81 html.add( text.substring(i2) ); | |
82 break; | |
83 } | |
84 html.add( comment( text.substring(i2+4,i) ) ); | |
85 i += 3; | |
86 } else if( text.startsWith("<![CDATA[",i2) ) { | |
87 i = text.indexOf("]]>",i2+9); | |
88 if( i == -1 ) { | |
89 html.add( text.substring(i2) ); | |
90 break; | |
91 } | |
92 html.add( cdata( text.substring(i2+9,i) ) ); | |
93 i += 3; | |
94 } else { | |
95 i = text.indexOf('>',i2); | |
96 if( i == -1 ) { | |
97 html.add( text.substring(i2) ); | |
98 break; | |
99 } | |
100 String tagText = text.substring(i2+1,i); | |
101 try { | |
102 LuanTable tag = parseTag(tagText); | |
103 String tagName = (String)tag.rawGet("name"); | |
104 if( containerTags.contains(tagName) ) { | |
105 i2 = i; | |
106 String endTagName = '/' + tagName; | |
107 while(true) { | |
108 i2 = text.indexOf('<',i2+1); | |
109 if( i2 == -1 ) | |
110 break; | |
111 int i3 = text.indexOf('>',i2); | |
112 if( i3 == -1 ) | |
113 break; | |
114 int j = i2+1; | |
115 while( j<i3 && !Character.isWhitespace(text.charAt(j)) ) j++; | |
116 String s = text.substring(i2+1,j); | |
117 if( s.equalsIgnoreCase(endTagName) ) { | |
118 String text2 = text.substring(i+1,i2); | |
119 LuanTable textContainer = textContainer(tag,text2); | |
120 html.add( textContainer ); | |
121 i = i3 + 1; | |
122 continue outer; | |
123 } | |
124 } | |
125 // logger.warn("unclosed "+tagName); | |
126 } | |
127 i += 1; | |
128 html.add( tag ); | |
129 } catch(BadTag e) { | |
130 // logger.debug("bad tag",e); | |
131 i += 1; | |
132 // if( !removeBadTags ) { | |
133 html.add( "<" ); | |
134 html.add( encode(luan,tagText) ); | |
135 html.add( ">" ); | |
136 // } | |
137 } | |
138 } | |
139 } | |
140 return new LuanTable(html); | |
141 } | |
142 | |
143 static LuanTable comment(String text) { | |
144 LuanTable tbl = new LuanTable(); | |
145 tbl.rawPut("type","comment"); | |
146 tbl.rawPut("text",text); | |
147 return tbl; | |
148 } | |
149 | |
150 static LuanTable cdata(String text) { | |
151 LuanTable tbl = new LuanTable(); | |
152 tbl.rawPut("type","cdata"); | |
153 tbl.rawPut("text",text); | |
154 return tbl; | |
155 } | |
156 | |
157 static LuanTable textContainer(LuanTable tag,String text) { | |
158 LuanTable tbl = new LuanTable(); | |
159 tbl.rawPut("type","container"); | |
160 tbl.rawPut("tag",tag); | |
161 tbl.rawPut("text",text); | |
162 return tbl; | |
163 } | |
164 | |
165 | |
166 | |
167 static final class BadTag extends RuntimeException { | |
168 private BadTag(String msg) { | |
169 super(msg); | |
170 } | |
171 } | |
172 | |
173 static LuanTable parseTag(String text) { | |
174 LuanTable tbl = new LuanTable(); | |
175 tbl.rawPut("type","tag"); | |
176 if( text.endsWith("/") ) { | |
177 text = text.substring(0,text.length()-1); | |
178 tbl.rawPut("is_empty",true); | |
179 } else { | |
180 tbl.rawPut("is_empty",false); | |
181 } | |
182 int len = text.length(); | |
183 int i = 0; | |
184 int i2 = i; | |
185 if( i2<len && text.charAt(i2)=='/' ) | |
186 i2++; | |
187 while( i2<len ) { | |
188 char c = text.charAt(i2); | |
189 if( Character.isWhitespace(c) ) | |
190 break; | |
191 if( !( Character.isLetterOrDigit(c) || c=='_' || c=='.' || c=='-' || c==':' ) ) | |
192 throw new BadTag("invalid tag name for <"+text+">"); | |
193 i2++; | |
194 } | |
195 String name = text.substring(i,i2).toLowerCase(); | |
196 tbl.rawPut("name",name); | |
197 LuanTable attributes = new LuanTable(); | |
198 tbl.rawPut("attributes",attributes); | |
199 i = i2; | |
200 while( i<len && Character.isWhitespace(text.charAt(i)) ) i++; | |
201 while( i<len ) { | |
202 i2 = toEndName(text,i,len); | |
203 String attrName = unquote(text.substring(i,i2).toLowerCase()); | |
204 if( attributes.rawGet(attrName) != null ) | |
205 throw new BadTag("duplicate attribute: "+attrName); | |
206 i = i2; | |
207 while( i<len && Character.isWhitespace(text.charAt(i)) ) i++; | |
208 if( i<len && text.charAt(i) == '=' ) { | |
209 i++; | |
210 i2 = i; | |
211 while( i<len && Character.isWhitespace(text.charAt(i)) ) i++; | |
212 i2 = toEndValue(text,i,len); | |
213 String attrValue = text.substring(i,i2); | |
214 if( attrValue.indexOf('<') != -1 || attrValue.indexOf('>') != -1 ) | |
215 throw new BadTag("invalid attribute value: "+attrValue); | |
216 attrValue = unquote(attrValue); | |
217 attributes.rawPut(attrName,attrValue); | |
218 i = i2; | |
219 while( i<len && Character.isWhitespace(text.charAt(i)) ) i++; | |
220 } else { | |
221 attributes.rawPut(attrName,true); | |
222 } | |
223 } | |
224 return tbl; | |
225 } | |
226 | |
227 private static int toEndName(String text,int i,int len) { | |
228 if( i==len ) | |
229 return i; | |
230 char c = text.charAt(i); | |
231 switch(c) { | |
232 case '"': | |
233 case '\'': | |
234 i = text.indexOf(c,i+1); | |
235 return i==-1 ? len : i+1; | |
236 default: | |
237 if( Character.isWhitespace(c) ) { | |
238 throw new RuntimeException("text="+text+" i="+i); | |
239 } | |
240 do { | |
241 i++; | |
242 } while( i<len && (c=text.charAt(i))!='=' && !Character.isWhitespace(c) ); | |
243 return i; | |
244 } | |
245 } | |
246 | |
247 private static int toEndValue(String text,int i,int len) { | |
248 if( i==len ) | |
249 return i; | |
250 char c = text.charAt(i); | |
251 switch(c) { | |
252 case '"': | |
253 case '\'': | |
254 i = text.indexOf(c,i+1); | |
255 return i==-1 ? len : i+1; | |
256 default: | |
257 if( Character.isWhitespace(c) ) { | |
258 throw new RuntimeException("text="+text+" i="+i); | |
259 } | |
260 do { | |
261 i++; | |
262 } while( i<len && !Character.isWhitespace(text.charAt(i)) ); | |
263 return i; | |
264 } | |
265 } | |
266 | |
267 public static String unquote(String s) { | |
268 if( s==null || s.length()<=1 ) | |
269 return s; | |
270 char c = s.charAt(0); | |
271 return (c=='"' || c=='\'') && s.charAt(s.length()-1)==c | |
272 ? s.substring(1,s.length()-1) : s; | |
273 } | |
274 */ | |
275 | |
276 | |
277 /* | |
278 public static String to_string(LuanState luan,LuanTable tbl) throws LuanException { | |
279 List<Object> html = tbl.asList(); | |
280 StringBuilder buf = new StringBuilder(); | |
281 for( Object o : html ) { | |
282 if( o instanceof String ) { | |
283 buf.append( o ); | |
284 } else if( o instanceof LuanTable ) { | |
285 LuanTable t = (LuanTable)o; | |
286 String type = (String)t.get(luan,"type"); | |
287 if( type==null ) | |
288 throw new LuanException(luan, "no type in element of table for 'Html.to_string'" ); | |
289 if( type.equals("comment") ) { | |
290 buf.append( "<!--" ).append( t.get(luan,"text") ).append( "-->" ); | |
291 } else if( type.equals("cdata") ) { | |
292 buf.append( "<![CDATA[" ).append( t.get(luan,"text") ).append( "]]" ); | |
293 } else if( type.equals("tag") ) { | |
294 buf.append( tagToString(luan,t) ); | |
295 } else if( type.equals("container") ) { | |
296 LuanTable tag = (LuanTable)t.get(luan,"tag"); | |
297 buf.append( tagToString(luan,tag) ); | |
298 buf.append( t.get(luan,"text") ); | |
299 buf.append( "</" ).append( tag.get(luan,"name") ).append( ">" ); | |
300 } else { | |
301 throw new LuanException(luan, "invalid element type for 'Html.to_string'" ); | |
302 } | |
303 } else | |
304 throw new LuanException(luan, "invalid value ("+Luan.type(o)+") in table for 'Html.to_string'" ); | |
305 } | |
306 return buf.toString(); | |
307 } | |
308 | |
309 private static String tagToString(LuanState luan,LuanTable tbl) throws LuanException { | |
310 StringBuilder buf = new StringBuilder(); | |
311 buf.append('<'); | |
312 buf.append(tbl.get(luan,"name")); | |
313 LuanTable attributes = (LuanTable)tbl.get(luan,"attributes"); | |
314 for( Map.Entry<Object,Object> attr : attributes.iterable(luan) ) { | |
315 buf.append( ' ' ); | |
316 buf.append( attr.getKey() ); | |
317 Object val = attr.getValue(); | |
318 if( !val.equals(Boolean.TRUE) ) { | |
319 buf.append( '=' ); | |
320 buf.append( quote((String)val) ); | |
321 } | |
322 } | |
323 if( tbl.get(luan,"is_empty").equals(Boolean.TRUE) ) | |
324 buf.append('/'); | |
325 buf.append('>'); | |
326 return buf.toString(); | |
327 } | |
328 */ | |
329 public static String quote(String s) { | |
330 StringBuilder buf = new StringBuilder(); | |
331 buf.append('"'); | |
332 int i = 0; | |
333 while(true) { | |
334 int i2 = s.indexOf('"',i); | |
335 if( i2 == -1 ) { | |
336 buf.append(s.substring(i)); | |
337 break; | |
338 } else { | |
339 buf.append(s.substring(i,i2)); | |
340 buf.append("""); | |
341 i = i2 + 1; | |
342 } | |
343 } | |
344 buf.append('"'); | |
345 return buf.toString(); | |
346 } | |
347 | |
348 } |