ElementDef.php 6.2 KB

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