1 /** 2 * Copyright: 3 * (C) 2016 Martin Brzenska 4 * 5 * License: 6 * Distributed under the terms of the MIT license. 7 * Consult the provided LICENSE.md file for details 8 */ 9 module libdominator.Attribute; 10 11 import std.regex : regex , matchFirst ; 12 import std.array : split; 13 14 import libdominator; 15 16 ///Struct for Node Attributes 17 struct Attribute 18 { 19 string key; 20 string[] values; 21 22 /** 23 * Params: 24 * key = the Name of the Attribute (can be prefixed with '(regex)') 25 * values = a whitespace serparated List of Attribute Values (each Value can be prefixed with '(regex)') 26 */ 27 this(string key, string values) 28 { 29 import std.string : toLower; 30 this.key = toLower(key); 31 this.values = split(values); 32 } 33 /** 34 * Params: 35 * key = The name of the attribute (can be prefixed with '(regex)') 36 * values = Array of attribute values (each value can be prefixed with '(regex)') 37 */ 38 this(string key, string[] values) 39 { 40 import std.string : toLower; 41 this.key = toLower(key); 42 this.values = values; 43 } 44 45 ///Checks if the given node matches the attributes given key 46 bool matchesKey(Node node) 47 { 48 if (key.length > 6 && key[0..7] == "(regex)") 49 { 50 auto regx = regex(key[7..$]); 51 foreach (Attribute attrib; node.getAttributes()) 52 { 53 auto capture = matchFirst(attrib.key, regx); 54 if (!capture.empty) 55 { 56 return true; 57 } 58 } 59 } 60 else 61 { 62 foreach (Attribute attrib; node.getAttributes()) 63 { 64 if (attrib.key == key) 65 { 66 return true; 67 } 68 } 69 } 70 return false; 71 } 72 ///Checks if at least one of the attribute values of the given node matches the given attribute values 73 bool matchesValue(Node node) 74 { 75 if (values.length == 0) 76 { 77 return true; 78 } 79 ubyte hitCount; 80 foreach (string value; values) 81 { 82 bool isRegex; 83 if (value.length > 6 && value[0 .. 7] == "(regex)") 84 { 85 isRegex =true; 86 } 87 foreach (Attribute attrib; node.getAttributes()) 88 { 89 foreach (string nodeValue; attrib.values) 90 { 91 if(isRegex) 92 { 93 auto capture = matchFirst(nodeValue, regex(value[7..$])); 94 if (!capture.empty) { hitCount++; } 95 } 96 else { 97 if (nodeValue == value) { hitCount++; } 98 } 99 if(hitCount == values.length) { return true; } 100 } 101 } 102 } 103 return false; 104 } 105 106 /** 107 * Checks if the given node matches key and values of this attribute. 108 * Note that all atribute values from this attribute must match the given nodes attribute values - not the other way round 109 */ 110 bool matches(Node node) 111 { 112 return this.matchesKey(node) && this.matchesValue(node); 113 } 114 115 }