/** COPYRIGHT © 2024 JOHN PEARCEY Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or copy at https://www.boost.org/LICENSE_1_0.txt) */ module attributeHandler; /** * Module mainly for attribute parsing for DB retrieval, and some other * common attribute functionality */ import std.stdio; /** * Simple attribute parser. * * Remember to escape the " and/or ' with " or ' if these values are required. */ class AttributeMap { string[string] attrib_map; this( string strAtts="" ){ if(strAtts!=""){ attrib_map = parse( strAtts ); } } string[string] getAttribMap( ){ return attrib_map; } int getAttribCount( ){ return cast(int)(attrib_map.length); } string getAttribute( string name ){ if( name in attrib_map ) return attrib_map[name]; return null; } string getAttsAsString(){ if(attrib_map.length==0) return ""; string rtn = ""; foreach( key; attrib_map.keys() ){ rtn ~= key ~ "=\"" ~ attrib_map[key] ~ "\" "; } return rtn; } void setAttribute( string name, string value){ attrib_map[name] = value; } void removeAttribute( string name ){ if( name in attrib_map ) attrib_map.remove(name); } static string[string] parse( string strAtts ){ string[string] mapAtts; int state = 0; string nxtKey = ""; string nxtVal = ""; char cQtp = '\0'; foreach( i,c; strAtts ){ switch(state){ case 0: // wait for a key switch(c){ case '>': //this is the end of the element tag return mapAtts; case ' ', '\t': break; default: state += 1; nxtKey ~= c; } break; case 1: //parsing a key switch(c){ case ' ': if(nxtKey=="") break; goto case '='; case '=': state += 1; break; default: nxtKey ~= c; } break; case 2: //waiting for a value switch(c){ case '"', '\'': cQtp = c; state += 1; break; case '=', ' ', '\t': break; default: // not a quote, must be the next attribute and the previous att has an empty value mapAtts[nxtKey] = ""; nxtKey = ""~c; state=0; } break; case 3: //looking for the value end, must be a quote switch(c){ case '"','\'': if(cQtp!=c){ nxtVal ~= c; break; } mapAtts[nxtKey] = nxtVal; nxtKey = ""; nxtVal = ""; state = 0; break; default: nxtVal ~= c; } break; default: } } return mapAtts; } } unittest{ writeln( "Testing attribute parsing" ); string strAtts = " color=\"red\" font='big font' nowrap v-align='top' border=\"\" "; AttributeMap atts = new AttributeMap( strAtts ); auto attMap = atts.getAttribMap(); foreach( key; attMap.keys() ){ string value = attMap[key]; switch(key){ case "color": assert( value=="red"); break; case "font": assert( value=="big font"); break; case "nowrap": case "border": assert( value==""); break; case "v-align": assert( value=="top"); break; default: writeln("unknown key was: ", key); assert(false); } } atts = new AttributeMap( "" ); attMap = atts.getAttribMap(); assert( attMap.length==0 ); atts = new AttributeMap( "color='pink' > other garbage" ); attMap = atts.getAttribMap(); assert( attMap.length==1 ); assert( attMap["color"]=="pink" ); }