Fixed bug #15092: Ajax loaded items of inline records are encoded twice (Thanks to...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_xml.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2010 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class for creating XML output from records
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
32 *
33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 86: class t3lib_xml
41 * 102: function t3lib_xml($topLevelName)
42 * 113: function setRecFields($table,$list)
43 * 122: function getResult()
44 * 132: function WAPHeader()
45 * 144: function renderHeader()
46 * 155: function renderFooter()
47 * 167: function newLevel($name,$beginEndFlag=0,$params=array())
48 * 192: function output($content)
49 * 208: function indent($b)
50 * 224: function renderRecords($table,$res)
51 * 237: function addRecord($table,$row)
52 * 255: function getRowInXML($table,$row)
53 * 271: function utf8($content)
54 * 281: function substNewline($string)
55 * 292: function fieldWrap($field,$value)
56 * 301: function WAPback()
57 * 315: function addLine($str)
58 *
59 * TOTAL FUNCTIONS: 17
60 * (This index is automatically created/updated by the extension "extdeveval")
61 *
62 */
63
64
65
66
67
68
69
70
71
72
73
74
75
76 /**
77 * XML class, Used to create XML output from input rows.
78 * Doesn't contain a lot of advanced features - pretty straight forward, practical stuff
79 * You are encouraged to use this class in your own applications.
80 *
81 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
82 * @package TYPO3
83 * @subpackage t3lib
84 * @see user_xmlversion, user_wapversion
85 */
86 class t3lib_xml {
87 var $topLevelName = 'typo3_test'; // Top element name
88 var $XML_recFields = array(); // Contains a list of fields for each table which should be presented in the XML output
89
90 var $XMLIndent=0;
91 var $Icode='';
92 var $XMLdebug=0;
93 var $includeNonEmptyValues=0; // if set, all fields from records are rendered no matter their content. If not set, only 'true' (that is '' or zero) fields make it to the document.
94 var $lines=array();
95
96 /**
97 * Constructor, setting topLevelName to the input var
98 *
99 * @param string Top Level Name
100 * @return void
101 */
102 function t3lib_xml($topLevelName) {
103 $this->topLevelName = $topLevelName;
104 }
105
106 /**
107 * When outputting a input record in XML only fields listed in $this->XML_recFields for the current table will be rendered.
108 *
109 * @param string Table name
110 * @param string Commalist of fields names from the table, $table, which is supposed to be rendered in the XML output. If a field is not in this list, it is not rendered.
111 * @return void
112 */
113 function setRecFields($table,$list) {
114 $this->XML_recFields[$table]=$list;
115 }
116
117 /**
118 * Returns the result of the XML rendering, basically this is imploding the internal ->lines array with linebreaks.
119 *
120 * @return string
121 */
122 function getResult() {
123 $content = implode(LF,$this->lines);
124 return $this->output($content);
125 }
126
127 /**
128 * Initialize WML (WAP) document with <?xml + <!DOCTYPE header tags and setting ->topLevelName as the first level.
129 *
130 * @return void
131 */
132 function WAPHeader() {
133 $this->lines[]='<?xml version="1.0"?>';
134 $this->lines[]='<!DOCTYPE '.$this->topLevelName.' PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">';
135 $this->newLevel($this->topLevelName,1);
136 }
137
138 /**
139 * Initialize "anonymous" XML document with <?xml + <!DOCTYPE header tags and setting ->topLevelName as the first level.
140 * Encoding is set to UTF-8!
141 *
142 * @return void
143 */
144 function renderHeader() {
145 $this->lines[]='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
146 $this->lines[]='<!DOCTYPE '.$this->topLevelName.'>';
147 $this->newLevel($this->topLevelName,1);
148 }
149
150 /**
151 * Sets the footer (of ->topLevelName)
152 *
153 * @return void
154 */
155 function renderFooter() {
156 $this->newLevel($this->topLevelName,0);
157 }
158
159 /**
160 * Indents/Outdents a new level named, $name
161 *
162 * @param string The name of the new element for this level
163 * @param boolean If false, then this function call will *end* the level, otherwise create it.
164 * @param array Array of attributes in key/value pairs which will be added to the element (tag), $name
165 * @return void
166 */
167 function newLevel($name,$beginEndFlag=0,$params=array()) {
168 if ($beginEndFlag) {
169 $pList='';
170 if (count($params)) {
171 $par=array();
172 foreach ($params as $key => $val) {
173 $par[]=$key.'="'.htmlspecialchars($val).'"';
174 }
175 $pList=' '.implode(' ',$par);
176 }
177 $this->lines[]=$this->Icode.'<'.$name.$pList.'>';
178 $this->indent(1);
179 } else {
180 $this->indent(0);
181 $this->lines[]=$this->Icode.'</'.$name.'>';
182 }
183 }
184
185 /**
186 * Function that will return the content from string $content. If the internal ->XMLdebug flag is set the content returned will be formatted in <pre>-tags
187 *
188 * @param string The XML content to output
189 * @return string Output
190 */
191 function output($content) {
192 if ($this->XMLdebug) {
193 return '<pre>'.htmlspecialchars($content).'</pre>
194 <hr /><font color="red">Size: '.strlen($content).'</font>';
195 } else {
196 return $content;
197 }
198 }
199
200 /**
201 * Increments/Decrements Indentation counter, ->XMLIndent
202 * Sets and returns ->Icode variable which is a line prefix consisting of a number of tab-chars corresponding to the indent-levels of the current posision (->XMLindent)
203 *
204 * @param boolean If true the XMLIndent var is increased, otherwise decreased
205 * @return string ->Icode - the prefix string with TAB-chars.
206 */
207 function indent($b) {
208 if ($b) $this->XMLIndent++; else $this->XMLIndent--;
209 $this->Icode='';
210 for ($a=0;$a<$this->XMLIndent;$a++) {
211 $this->Icode.=TAB;
212 }
213 return $this->Icode;
214 }
215
216 /**
217 * Takes a SQL result for $table and traverses it, adding rows
218 *
219 * @param string Tablename
220 * @param pointer SQL resource pointer, should be reset
221 * @return void
222 */
223 function renderRecords($table,$res) {
224 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
225 $this->addRecord($table,$row);
226 }
227 }
228
229 /**
230 * Adds record, $row, from table, $table, to the internal array of XML-lines
231 *
232 * @param string Table name
233 * @param array The row to add to XML structure from the table name
234 * @return void
235 */
236 function addRecord($table,$row) {
237 $this->lines[]=$this->Icode.'<'.$table.' uid="'.$row["uid"].'">';
238 $this->indent(1);
239 $this->getRowInXML($table,$row);
240 $this->indent(0);
241 $this->lines[]=$this->Icode.'</'.$table.'>';
242 }
243
244 /**
245 * Internal function for adding the actual content of the $row from $table to the internal structure.
246 * Notice that only fields from $table that are listed in $this->XML_recFields[$table] (set by setRecFields()) will be rendered (and in the order found in that array!)
247 * Content from the row will be htmlspecialchar()'ed, UTF-8 encoded and have LF (newlines) exchanged for '<newline/>' tags. The element name for a value equals the fieldname from the record.
248 *
249 * @param string Table name
250 * @param array Row from table to add.
251 * @return void
252 * @access private
253 */
254 function getRowInXML($table,$row) {
255 $fields = t3lib_div::trimExplode(',',$this->XML_recFields[$table],1);
256 foreach ($fields as $field) {
257 if ($row[$field] || $this->includeNonEmptyValues) {
258 $this->lines[]=$this->Icode.$this->fieldWrap($field,$this->substNewline($this->utf8(htmlspecialchars($row[$field]))));
259 }
260 }
261 }
262
263 /**
264 * UTF-8 encodes the input content (from ISO-8859-1!)
265 *
266 * @param string String content to UTF-8 encode
267 * @return string Encoded content.
268 */
269 function utf8($content) {
270 return utf8_encode($content);
271 }
272
273 /**
274 * Substitutes LF characters with a '<newline/>' tag.
275 *
276 * @param string Input value
277 * @return string Processed input value
278 */
279 function substNewline($string) {
280 return str_replace(LF,'<newline/>',$string);
281 }
282
283 /**
284 * Wraps the value in tags with element name, $field.
285 *
286 * @param string Fieldname from a record - will be the element name
287 * @param string Value from the field - will be wrapped in the elements.
288 * @return string The wrapped string.
289 */
290 function fieldWrap($field,$value) {
291 return '<'.$field.'>'.$value.'</'.$field.'>';
292 }
293
294 /**
295 * Creates the BACK button for WAP documents
296 *
297 * @return void
298 */
299 function WAPback() {
300 $this->newLevel('template',1);
301 $this->newLevel('do',1,array('type'=>'accept','label'=>'Back'));
302 $this->addLine('<prev/>');
303 $this->newLevel('do');
304 $this->newLevel('template');
305 }
306
307 /**
308 * Add a line to the internal XML structure (automatically prefixed with ->Icode.
309 *
310 * @param string Line to add to the $this->lines array
311 * @return void
312 */
313 function addLine($str) {
314 $this->lines[]=$this->Icode.$str;
315 }
316 }
317
318
319 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_xml.php']) {
320 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_xml.php']);
321 }
322 ?>