📄 xml.csp
字号:
//|
//| xml package
//| TIL language (http://terra-informatica.org)
//| author: Andrew Fedoniuk
package xml;
function escape(t) {
return t.replace('&',"&",'<',"<",'>',">",'"',""",'\'',"'");
}
function unescape(t)
{
if(t.like("*&*;*")) return t.replace("<",'<',">",'>',""",'"',"'",'\'',"&",'&');
/* TODO char codes */
return t;
}
//|
//| micro DOM implementation
//|
class node {
var _value;
function node(v) { _value = v; }
function toString() { return "\n<!--WARNING:toString not defined-->\n" ; }
}
class pi: node {
function pi(v) { node(v); }
function toString() { return string::printf("<?%s?>",unescape(_value)) ; }
}
class comment: node {
function comment(v) { node(v); }
function toString() { return string::printf("<!--%s-->",unescape(_value)); }
}
class cdata: node {
function cdata(v) { node(v); }
function toString() { return string::printf("![CDATA[%s]]>",unescape(_value)); }
}
//|
//| simple element has only text value, no children
//|
class simple_element: node {
var _name;
var _attributes;
function simple_element(name,atts,content) {
node(content);
_name = name;
_attributes = atts;
}
//|
//| access to children in form of property
//|
property children() { /* nothing here */ return null; }
//|
//| access to attributes
//| e.g. : a = xnode["name"];
//|
function [](n,v)
{
if(!is_undefined(v)) // set
{
if(!_attributes) _attributes = new map();
_attributes[n] = v;
return v;
}
if(_attributes) return _attributes[n];
return null;
}
//|
//| value here is just all text children
//| always returns string
//|
property value(v) {
// read/write
if(!is_undefined(v)) _value = v;
return _value;
}
//|
//| creates string representation of content
//| always returns string
//|
function valueToString() {
//out.printf("DEBUG: (%s) valueToString\n",_name);
if(_value) return unescape(_value);
return "";
}
function toString() {
var i;
var s = "<" + _name;
if(_attributes)
for (i = 0; i < _attributes.length; i++)
s += string::printf(" %s=\"%s\"",_attributes.key(i),unescape(_attributes.value(i)));
if(_value)
s += (" >" + valueToString() + string::printf("</%s>", _name));
else
s += " />";
return s;
}
}
//|
//| element has text value(s) and/or children
//|
class element: simple_element
{
function element(name,atts,content) { simple_element(name,atts,content); }
//|
//| value here is just all text children
//| always returns string
//|
property value() {
// read only
if(!_value) return "";
var i,v = "";
for(i = 0; i < _value.length; i++) if(is_string(_value[i])) v += _value[i];
return v;
}
//|
//| returns first element with the given tag_name
//|
function child(tag_name)
{
if(_value) {
var i;
for(i = 0; i < _value.length; i++)
if( (_value[i] instanceof xml::simple_element) &&
(_value[i]._name == tag_name) ) return _value[i];
}
return null;
}
//|
//| tag_name here is template of tag name.
//| returns 1) array of subelements with the given tag_name
//| or 2) map of subelements with the given tag_name and having attribute att_name.
//| key of the map is value of att_name (these values supposed to be unique
//| among all children of given element)
//|
function elements(tag_name,att_name)
{
var r;
if(att_name) // map
{
r = new map();
if(!_value) return r;
var i;
for(i = 0; i < _value.length; i++)
{
var el = _value[i];
if( el instanceof xml::simple_element && el._name.like(tag_name))
{
var a = el[att_name];
if( a ) r[a] = el;
}
}
} else { // array
r = new array();
if(!_value) return r;
var i;
for(i = 0; i < _value.length; i++)
{
var el = _value[i];
if( el instanceof simple_element && el._name.like(tag_name))
r.push(el);
}
}
return r;
}
function valueToString() {
if(_value)
{
var i,v = "";
for(i = 0; i < _value.length; i++)
v += is_string(_value[i])? unescape(_value[i]): string(_value[i]);
return v;
}
return "";
}
}
//|
//| idee fixe
//|
class parser {
var _in;
var _error_msg;
var _error_ln;
var _got_eot;
// vocabulary for interning nmtokens
static var voc = new map();
function parser() { _in = null; }
function intern(nmtoken) {
if( !voc.exist(nmtoken) ) voc[nmtoken] = nmtoken;
return voc[nmtoken];
}
function compile_atts() {
var atts;
while(true) {
var n = _in.get('=',"/>",">").trim();
if(_in.get_match == 2) _got_eot = true;
if(_in.get_match != 1) break;
if(!n) throw "empty name encountered";
var z = _in.get('\"','\'',"/>",">").trim();
if( z ) throw string::printf("bad attribute definition (%s)", n );
if(_in.get_match > 2) throw "empty value encountered";
var v = _in.get( _in.get_match == 1 ? '\"' : '\'' );
if(!atts) atts = new map();
atts[ intern(n) ] = unescape(v);
}
return atts;
}
function compile_tag(tag_name)
{
//NB already got '<'
var c = _in.get(); // get one char
switch(c)
{
case '/':
{
var n = _in.get('>').trim(); // get until (exclusive)
if(tag_name != n) throw string::printf("tag '%s' not closed (%s)",tag_name,n);
return null;
}
case '?':
{
var v = _in.get("?>");
return new pi(v);
}
case '!':
{
c = _in.get();
if ( c == '-' )
{
if(_in.get() != '-') throw string::printf("bad comment: %s",_in.get("\n"));
var v = _in.get("-->");
return new comment(v);
}
else if ( c == '[' ) {
var v = _in.get("CDATA[","\n");
if(v) throw string::printf("expecting:'CDATA[', got:%s",v);
v = _in.get("]]>");
return new cdata(v);
}
else if( c == 'D' )
{
//skip doctype definition
_in.get("OCTYPE");
_in.get("]");_in.get(">");
return true;
}
else
throw string::printf("expecting comment or cdata, got '%c'",c);
} break;
default:
{
var atts_map;
_got_eot = false;
var name = intern( new string(c) + _in.get(' ',"/>",'>').trim() );
if(_in.get_match == 1) atts_map = compile_atts(_in);
else if(_in.get_match == 2) _got_eot = true;
var content;
if(!_got_eot)
while(!_in.eof)
{
var v = _in.get('<');
//out.printf("DEBUG: (%s) content (%s)\n",name,content);
if(v)
{
if(!content) // make it string
content = unescape(v);
else // array
content.push(unescape(v));
}
v = compile_tag(name);
if(v) {
if( !is_array(content) ) content = content? new array(content) : new array();
content.push(v);
}
else // this was tail of this tag
break;
}
return is_array(content)?
new element(name,atts_map,content):
new simple_element(name,atts_map,content);
}
}
}
function parse(in_stream)
{
_in = in_stream;
var r = null;
try {
do {
if( typeof(_in.get('<')) == type::NULL) break;
r = compile_tag(".");
//skiping all pi's and doctypes
} while( !(r instanceof simple_element) ); // or element
} catch (e) { std::out.printf("ERROR:%s",e); }
_in.close();
return r;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -