1 : <?php
2 :
3 : /**
4 : * Structure that stores an HTML element definition. Used by
5 : * HTMLPurifier_HTMLDefinition and HTMLPurifier_HTMLModule.
6 : * @note This class is inspected by HTMLPurifier_Printer_HTMLDefinition.
7 : * Please update that class too.
8 : */
9 : class HTMLPurifier_ElementDef
10 1 : {
11 :
12 : /**
13 : * Does the definition work by itself, or is it created solely
14 : * for the purpose of merging into another definition?
15 : */
16 : public $standalone = true;
17 :
18 : /**
19 : * Associative array of attribute name to HTMLPurifier_AttrDef
20 : * @note Before being processed by HTMLPurifier_AttrCollections
21 : * when modules are finalized during
22 : * HTMLPurifier_HTMLDefinition->setup(), this array may also
23 : * contain an array at index 0 that indicates which attribute
24 : * collections to load into the full array. It may also
25 : * contain string indentifiers in lieu of HTMLPurifier_AttrDef,
26 : * see HTMLPurifier_AttrTypes on how they are expanded during
27 : * HTMLPurifier_HTMLDefinition->setup() processing.
28 : */
29 : public $attr = array();
30 :
31 : /**
32 : * Indexed list of tag's HTMLPurifier_AttrTransform to be done before validation
33 : */
34 : public $attr_transform_pre = array();
35 :
36 : /**
37 : * Indexed list of tag's HTMLPurifier_AttrTransform to be done after validation
38 : */
39 : public $attr_transform_post = array();
40 :
41 : /**
42 : * HTMLPurifier_ChildDef of this tag.
43 : */
44 : public $child;
45 :
46 : /**
47 : * Abstract string representation of internal ChildDef rules. See
48 : * HTMLPurifier_ContentSets for how this is parsed and then transformed
49 : * into an HTMLPurifier_ChildDef.
50 : * @warning This is a temporary variable that is not available after
51 : * being processed by HTMLDefinition
52 : */
53 : public $content_model;
54 :
55 : /**
56 : * Value of $child->type, used to determine which ChildDef to use,
57 : * used in combination with $content_model.
58 : * @warning This must be lowercase
59 : * @warning This is a temporary variable that is not available after
60 : * being processed by HTMLDefinition
61 : */
62 : public $content_model_type;
63 :
64 :
65 :
66 : /**
67 : * Does the element have a content model (#PCDATA | Inline)*? This
68 : * is important for chameleon ins and del processing in
69 : * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't
70 : * have to worry about this one.
71 : */
72 : public $descendants_are_inline = false;
73 :
74 : /**
75 : * List of the names of required attributes this element has. Dynamically
76 : * populated by HTMLPurifier_HTMLDefinition::getElement
77 : */
78 : public $required_attr = array();
79 :
80 : /**
81 : * Lookup table of tags excluded from all descendants of this tag.
82 : * @note SGML permits exclusions for all descendants, but this is
83 : * not possible with DTDs or XML Schemas. W3C has elected to
84 : * use complicated compositions of content_models to simulate
85 : * exclusion for children, but we go the simpler, SGML-style
86 : * route of flat-out exclusions, which correctly apply to
87 : * all descendants and not just children. Note that the XHTML
88 : * Modularization Abstract Modules are blithely unaware of such
89 : * distinctions.
90 : */
91 : public $excludes = array();
92 :
93 : /**
94 : * Low-level factory constructor for creating new standalone element defs
95 : */
96 : public static function create($content_model, $content_model_type, $attr) {
97 : $def = new HTMLPurifier_ElementDef();
98 : $def->content_model = $content_model;
99 : $def->content_model_type = $content_model_type;
100 : $def->attr = $attr;
101 : return $def;
102 : }
103 :
104 : /**
105 : * Merges the values of another element definition into this one.
106 : * Values from the new element def take precedence if a value is
107 : * not mergeable.
108 : */
109 : public function mergeIn($def) {
110 :
111 : // later keys takes precedence
112 0 : foreach($def->attr as $k => $v) {
113 0 : if ($k === 0) {
114 : // merge in the includes
115 : // sorry, no way to override an include
116 0 : foreach ($v as $v2) {
117 0 : $this->attr[0][] = $v2;
118 0 : }
119 0 : continue;
120 0 : }
121 0 : if ($v === false) {
122 0 : if (isset($this->attr[$k])) unset($this->attr[$k]);
123 0 : continue;
124 0 : }
125 0 : $this->attr[$k] = $v;
126 0 : }
127 0 : $this->_mergeAssocArray($this->attr_transform_pre, $def->attr_transform_pre);
128 0 : $this->_mergeAssocArray($this->attr_transform_post, $def->attr_transform_post);
129 0 : $this->_mergeAssocArray($this->excludes, $def->excludes);
130 :
131 0 : if(!empty($def->content_model)) {
132 0 : $this->content_model .= ' | ' . $def->content_model;
133 0 : $this->child = false;
134 0 : }
135 0 : if(!empty($def->content_model_type)) {
136 0 : $this->content_model_type = $def->content_model_type;
137 0 : $this->child = false;
138 0 : }
139 0 : if(!is_null($def->child)) $this->child = $def->child;
140 0 : if($def->descendants_are_inline) $this->descendants_are_inline = $def->descendants_are_inline;
141 :
142 0 : }
143 :
144 : /**
145 : * Merges one array into another, removes values which equal false
146 : * @param $a1 Array by reference that is merged into
147 : * @param $a2 Array that merges into $a1
148 : */
149 : private function _mergeAssocArray(&$a1, $a2) {
150 0 : foreach ($a2 as $k => $v) {
151 0 : if ($v === false) {
152 0 : if (isset($a1[$k])) unset($a1[$k]);
153 0 : continue;
154 0 : }
155 0 : $a1[$k] = $v;
156 0 : }
157 0 : }
158 :
159 : }
160 :
161 :
|