Newer
Older
dom-persist / source / attributeHandler.d
  1. module attributeHandler;
  2.  
  3. /**
  4. * Module mainly for attribute parsing for DB retrieval, and some other
  5. * common attribute functionality
  6. */
  7.  
  8. import std.stdio;
  9.  
  10.  
  11. /**
  12. * Simple attribute parser.
  13. *
  14. * Remember to escape the " and/or ' with " or ' if these values are required.
  15. */
  16. class AttributeMap {
  17. string[string] attrib_map;
  18. this( string strAtts="" ){
  19. if(strAtts!=""){
  20. attrib_map = parse( strAtts );
  21. }
  22. }
  23. string[string] getAttribMap( ){
  24. return attrib_map;
  25. }
  26. int getAttribCount( ){
  27. return cast(int)(attrib_map.length);
  28. }
  29.  
  30. string getAttribute( string name ){
  31. if( name in attrib_map ) return attrib_map[name];
  32. return null;
  33. }
  34. string getAttsAsString(){
  35. if(attrib_map.length==0) return "";
  36. string rtn = "";
  37. foreach( key; attrib_map.keys() ){
  38. rtn ~= key ~ "=\"" ~ attrib_map[key] ~ "\" ";
  39. }
  40. return rtn;
  41. }
  42. void setAttribute( string name, string value){
  43. attrib_map[name] = value;
  44. }
  45. void removeAttribute( string name ){
  46. if( name in attrib_map ) attrib_map.remove(name);
  47. }
  48. static string[string] parse( string strAtts ){
  49. string[string] mapAtts;
  50. int state = 0;
  51. string nxtKey = "";
  52. string nxtVal = "";
  53. char cQtp = '\0';
  54. foreach( i,c; strAtts ){
  55. switch(state){
  56. case 0:
  57. // wait for a key
  58. switch(c){
  59. case '>':
  60. //this is the end of the element tag
  61. return mapAtts;
  62. case ' ', '\t':
  63. break;
  64. default:
  65. state += 1;
  66. nxtKey ~= c;
  67. }
  68. break;
  69. case 1:
  70. //parsing a key
  71. switch(c){
  72. case ' ':
  73. if(nxtKey=="") break;
  74. goto case '=';
  75. case '=':
  76. state += 1;
  77. break;
  78.  
  79. default:
  80. nxtKey ~= c;
  81. }
  82. break;
  83. case 2:
  84. //waiting for a value
  85. switch(c){
  86. case '"', '\'':
  87. cQtp = c;
  88. state += 1;
  89. break;
  90. case '=', ' ', '\t':
  91. break;
  92. default:
  93. // not a quote, must be the next attribute and the previous att has an empty value
  94. mapAtts[nxtKey] = "";
  95. nxtKey = ""~c;
  96. state=0;
  97. }
  98. break;
  99. case 3:
  100. //looking for the value end, must be a quote
  101. switch(c){
  102. case '"','\'':
  103. if(cQtp!=c){
  104. nxtVal ~= c;
  105. break;
  106. }
  107. mapAtts[nxtKey] = nxtVal;
  108. nxtKey = "";
  109. nxtVal = "";
  110. state = 0;
  111. break;
  112. default:
  113. nxtVal ~= c;
  114. }
  115. break;
  116.  
  117. default:
  118. }
  119. }
  120. return mapAtts;
  121. }
  122. }
  123.  
  124.  
  125. unittest{
  126.  
  127. writeln( "Testing attribute parsing" );
  128.  
  129. string strAtts = " color=\"red\" font='big font' nowrap v-align='top' border=\"\" ";
  130. AttributeMap atts = new AttributeMap( strAtts );
  131. auto attMap = atts.getAttribMap();
  132. foreach( key; attMap.keys() ){
  133. string value = attMap[key];
  134. switch(key){
  135. case "color":
  136. assert( value=="red");
  137. break;
  138. case "font":
  139. assert( value=="big font");
  140. break;
  141. case "nowrap":
  142. case "border":
  143. assert( value=="");
  144. break;
  145. case "v-align":
  146. assert( value=="top");
  147. break;
  148. default:
  149. writeln("unknown key was: ", key);
  150. assert(false);
  151. }
  152. }
  153.  
  154. atts = new AttributeMap( "" );
  155. attMap = atts.getAttribMap();
  156. assert( attMap.length==0 );
  157.  
  158. atts = new AttributeMap( "color='pink' > other garbage" );
  159. attMap = atts.getAttribMap();
  160. assert( attMap.length==1 );
  161. assert( attMap["color"]=="pink" );
  162. }