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         this.key = key;
41         this.values = values;
42     }
43 
44     ///Checks if the given node matches the attributes given key
45     bool matchesKey(Node node)
46     {
47         if (key.length > 6 && key[0..7] == "(regex)")
48         {
49             auto regx = regex(key[7..$]);
50             foreach (Attribute attrib; node.getAttributes())
51             {
52                 auto capture = matchFirst(attrib.key, regx);
53                 if (!capture.empty)
54                 {
55                     return true;
56                 }
57             }
58         }
59         else
60         {
61             foreach (Attribute attrib; node.getAttributes())
62             {
63                 if (attrib.key == key)
64                 {
65                     return true;
66                 }
67             }
68         }
69         return false;
70     }
71     ///Checks if at least one of the attribute values of the given node matches the given attribute values
72     bool matchesValue(Node node)
73     {
74         if (values.length == 0)
75         {
76             return true;
77         }
78         ubyte hitCount;
79         foreach (string value; values)
80         {
81             bool isRegex;
82             if (value.length > 6 && value[0 .. 7] == "(regex)")
83             {
84                 isRegex =true;
85             }
86             foreach (Attribute attrib; node.getAttributes())
87             {
88                 foreach (string nodeValue; attrib.values)
89                 {
90                     if(isRegex)
91                     {
92                         auto capture = matchFirst(nodeValue, regex(value[7..$]));
93                         if (!capture.empty) { hitCount++; }
94                     }
95                     else {
96                         if (nodeValue == value) { hitCount++; }
97                     }
98                     if(hitCount == values.length) { return true; }
99                 }
100             }
101         }
102         return false;
103     }
104 
105     /**
106     * Checks if the given node matches key and values of this attribute.
107     * Note that all atribute values from this attribute must match the given nodes attribute values - not the other way round
108     */
109     bool matches(Node node)
110     {
111         return this.matchesKey(node) && this.matchesValue(node);
112     }
113 
114 }