1<?php
2/**
3 * Data structures used in parsing XML DocBook-based tutorials
4 *
5 * Conversion of DocBook-based tutorials is performed using special
6 * {@link Converter} class methods.  By default, these methods simply retrieve
7 * simple rules for replacement of tags and slight re-ordering from the
8 * options.ini file present for every template.
9 *
10 * In future versions, there may be utilization of xslt or other more powerful
11 * protocols.  However, for most situations, the power of these classes will
12 * be more than sufficient to handle very complex documentation.
13 *
14 * Note that an entire tutorial is contained in a single parserXMLDocBookTag,
15 * matching the document model for DocBook.  The top-level tag, <refentry>,
16 * contains every other tag and all text.
17 *
18 * phpDocumentor :: automatic documentation generator
19 *
20 * PHP versions 4 and 5
21 *
22 * Copyright (c) 2002-2008 Gregory Beaver
23 *
24 * LICENSE:
25 *
26 * This library is free software; you can redistribute it
27 * and/or modify it under the terms of the GNU Lesser General
28 * Public License as published by the Free Software Foundation;
29 * either version 2.1 of the License, or (at your option) any
30 * later version.
31 *
32 * This library is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Lesser General Public License for more details.
36 *
37 * You should have received a copy of the GNU Lesser General Public
38 * License along with this library; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 *
41 * @category   ToolsAndUtilities
42 * @package    phpDocumentor
43 * @subpackage Tutorial
44 * @author     Gregory Beaver <cellog@php.net>
45 * @copyright  2002-2008 Gregory Beaver
46 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
47 * @version    CVS: $Id: PackagePageElements.inc 253643 2008-02-24 04:27:54Z ashnazg $
48 * @tutorial   tutorials.pkg
49 * @link       http://www.phpdoc.org
50 * @link       http://pear.php.net/PhpDocumentor
51 * @since      1.2.0
52 * @todo       CS cleanup - change package to PhpDocumentor
53 */
54/**
55 * Represents <![CDATA[ ]]> sections.
56 *
57 * These sections are interpreted as plain text
58 *
59 * @category   ToolsAndUtilities
60 * @package    phpDocumentor
61 * @subpackage Tutorial
62 * @author     Gregory Beaver <cellog@php.net>
63 * @copyright  2002-2008 Gregory Beaver
64 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
65 * @version    Release: 1.4.4
66 * @tutorial   tutorials.pkg
67 * @link       http://www.phpdoc.org
68 * @link       http://pear.php.net/PhpDocumentor
69 * @todo       CS cleanup - change package to PhpDocumentor
70 * @todo       CS cleanup - change classname to PhpDocumentor_*
71 */
72class parserCData extends parserStringWithInlineTags
73{
74    /**
75     * calls the output conversion
76     *
77     * @param Converter &$c          the output converter
78     * @param bool      $postprocess if postprocessing is needed
79     *
80     * @return string
81     * @uses Converter::getCData() convert contents to text
82     * @todo CS cleanup - rename to convert for camelCase rule
83     */
84    function Convert(&$c, $postprocess = true)
85    {
86        $val = $this->value;
87        if ($postprocess) {
88            foreach ($this->value as $key => $value) {
89                if (is_string($value)) {
90                    $this->value[$key] = $c->getCData($value);
91                }
92            }
93        }
94        $this->cache = false;
95        $x           = parent::Convert($c, false);
96        $this->value = $val;
97        return $x;
98    }
99}
100/**
101 * a standard XML DocBook Tag
102 *
103 * This class is designed to represent all DocBook tags.  It is intelligent
104 * enough to understand the <title> tag, and also the <refname> tag for
105 * as title for <refentry>
106 *
107 * @category   ToolsAndUtilities
108 * @package    phpDocumentor
109 * @subpackage Tutorial
110 * @author     Gregory Beaver <cellog@php.net>
111 * @copyright  2002-2008 Gregory Beaver
112 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
113 * @version    Release: 1.4.4
114 * @tutorial   tutorials.pkg
115 * @link       http://www.phpdoc.org
116 * @link       http://pear.php.net/PhpDocumentor
117 * @since      1.2
118 * @todo       CS cleanup - change package to PhpDocumentor
119 * @todo       CS cleanup - change classname to PhpDocumentor_*
120 * @todo       CS cleanup - rename to parserXmlDocBookTag for camelCase rule
121 */
122class parserXMLDocBookTag extends parserStringWithInlineTags
123{
124    /**
125     * Attributes from the XML tag
126     *
127     * Format: array(attrname => attrvalue, attrname => attrvalue,...)
128     * @var array
129     */
130    var $attributes = array();
131    /**
132     * Name of the tag
133     * @var string
134     */
135    var $name;
136    /**#@+
137     * @access private
138     */
139    /**
140     * @var parserCData
141     */
142    var $_cdata;
143    /**
144     * @var parserTag
145     */
146    var $_title;
147    /**
148     * @var parserIdLineTag
149     */
150    var $_id;
151    /**
152     * Set to <refpurpose> in <refsynopsisdiv>
153     * @var parserTag
154     */
155    var $_description;
156    /**#@-*/
157
158    /**
159     * sets up the tag
160     *
161     * @param string $name tag name
162     *
163     * @todo CS cleanup - rename to parserXmlDocBookTag for camelCase rule
164     */
165    function parserXMLDocBookTag($name)
166    {
167        $this->name = $name;
168    }
169
170    /**
171     * calls the output conversion
172     *
173     * @param Converter &$c          the output converter
174     * @param bool      $postprocess if postprocessing is needed
175     *
176     * @return string
177     * @uses Converter::TranslateTag() Calls this to enclose the contents of the
178     *       DocBook tag based on the values in template options.ini file
179     */
180    function Convert(&$c, $postprocess = true)
181    {
182        $value    = parent::Convert($c, $postprocess);
183        $simvalue = parent::Convert($c, false);
184        foreach ($this->attributes as $a => $v) {
185            $this->attributes[$a] = (is_string($v) ? $v :
186                $v->Convert($c, $postprocess));
187        }
188        if (isset($this->_title)) {
189            list($this->attributes,$value) = $c->ConvertTitle($this->name,
190                $this->attributes, $this->_title->Convert($c, $postprocess), $value);
191        }
192        return $c->TranslateTag($this->name, $this->attributes, $value, $simvalue);
193    }
194
195    /**
196     * Begin a new CData section
197     *
198     * @return void
199     * @see addCData()
200     */
201    function startCData()
202    {
203        $this->_cdata = new parserCData;
204    }
205
206    /**
207     * Adds {@link $_cdata} to {@link $value}
208     *
209     * @return void
210     */
211    function endCData()
212    {
213        $this->value[] = $this->_cdata;
214        unset($this->_cdata);
215    }
216
217    /**
218     * Retrieve either the table of contents index,
219     * or the location that the TOC will go
220     *
221     * @param false|integer $state either an index of the {@}toc} tag in $this->value
222     *                             or false, if the next index value of $this->value
223     *                             is needed
224     *
225     * @return int
226     * @see setTOC()
227     */
228    function getTOC($state = false)
229    {
230        if ($state !== false) {
231            return $this->value[$state];
232        }
233        return count($this->value);
234    }
235
236    /**
237     * sets the TOC value
238     *
239     * @param integer            $state index of the TOC in $this->value
240     * @param parserTocInlineTag $val   tag value
241     *
242     * @return void
243     */
244    function setTOC($state, $val)
245    {
246        $this->value[$state] = $val;
247    }
248
249    /**
250     * add a word to CData
251     *
252     * @param string $word word to add
253     *
254     * @return void
255     */
256    function addCData($word)
257    {
258        $this->_cdata->add($word);
259    }
260
261    /**
262     * Add an xml tag attribute name="value" pair
263     *
264     * if the attribute is id, value must be a {@link parserIdInlineTag}
265     *
266     * @param string                   $name  attribute name
267     * @param string|parserIdInlineTag $value value of attribute
268     *
269     * @return void
270     */
271    function addAttribute($name, $value)
272    {
273        $this->attributes[$name] = $value;
274        if ($name == 'id') {
275            // fix 1153593
276            if (is_string($value)) {
277                addWarning(PDERROR_ID_MUST_BE_INLINE, $this->name, $value,
278                    $this->name, $value);
279            } else {
280                $this->setId($value);
281            }
282        }
283    }
284
285    /**
286     * Set the title of a DocBook tag section.
287     *
288     * For most DocBook tags, the title is represented with a <title></title>
289     * tag pair.  The <refentry> top-level tag is a little different.  Instead
290     * of using <title></title>, phpDocumentor uses the contents of the
291     * <refname> tag in the <refnamediv> tag
292     *
293     * @param parserXMLDocBookTag $title the title element
294     *
295     * @return void
296     */
297    function setTitle($title)
298    {
299        $this->_title = $title;
300    }
301
302    /**
303     * If the id attribute is present, this method will set its id
304     *
305     * @param parserIdInlineTag $id the id value
306     *
307     * @return void
308     */
309    function setId($id)
310    {
311        $this->_id = $id;
312    }
313
314    /**
315     * Return converter-specific formatting of ID.
316     *
317     * Passes $c to {@link parserIdInlineTag::Convert()}
318     *
319     * @param Converter &$c the output converter
320     *
321     * @return string
322     */
323    function getId(&$c)
324    {
325        if ($this->_id) {
326            return trim($this->_id->Convert($c));
327        }
328    }
329
330    /**
331     * Determine whether the docbook element has a title
332     *
333     * @return boolean
334     */
335    function hasTitle()
336    {
337        return isset($this->_title);
338    }
339
340    /**
341     * Retrieve Converter-specific formatting of the title of this element
342     *
343     * @param Converter &$c the output converter
344     *
345     * @return string
346     */
347    function getTitle(&$c)
348    {
349        if ($this->name == 'refentry') {
350            foreach ($this->value as $tag) {
351                if (is_object($tag) && $tag->name == 'refnamediv') {
352                    return $tag->getTitle($c);
353                }
354            }
355        }
356        if ($this->name == 'refnamediv') {
357            foreach ($this->value as $tag) {
358                if (is_object($tag) && is_a($tag, 'parserXMLDocBookTag')
359                    && $tag->name == 'refname') {
360                    $t = new parserStringWithInlineTags;
361                    foreach ($tag->value as $val) {
362                        $t->add($val);
363                    }
364                    $this->_title = $t;
365                }
366                if (is_object($tag) && is_a($tag, 'parserXMLDocBookTag')
367                    && $tag->name == 'refpurpose') {
368                    $t = new parserStringWithInlineTags;
369                    foreach ($tag->value as $val) {
370                        $t->add($val);
371                    }
372                    $this->_description = $t;
373                }
374            }
375        }
376        if (isset($this->_title)) {
377            return $this->_title->Convert($c);
378        }
379        if (is_object($this->value[0]) && is_a($tag, 'parserXMLDocBookTag')) {
380            return $this->value[0]->getTitle($c);
381        }
382        if (isset($this->value[1])) {
383            if (is_object($this->value[1]) && is_a($tag, 'parserXMLDocBookTag')) {
384                return $this->value[1]->getTitle($c);
385            }
386        }
387        return '';
388    }
389
390    /**
391     * Retrieve the contents of a subsection
392     *
393     * This method uses the $_id members of nested docbook tags to retrieve
394     * the section defined by $subsection
395     *
396     * @param Converter &$c         the output converter
397     * @param string    $subsection converter-specific subsection
398     *
399     * @return bool|string
400     */
401    function getSubsection(&$c, $subsection)
402    {
403        if (!is_object($this->_id)) {
404            return false;
405        }
406        $search = phpDocumentor_clone($this->_id);
407        if (is_string($this->_id)) {
408            return false;
409        }
410        if (phpDocumentor_get_class($search) != 'parseridinlinetag') {
411            return false;
412        }
413        $search->id = $subsection;
414        foreach ($this->value as $el) {
415            if (phpDocumentor_get_class($el) == 'parserxmldocbooktag') {
416                if ($el->getId($c) == $search->Convert($c)) {
417                    return $el;
418                } elseif ($a = $el->getSubsection($c, $subsection)) {
419                    return $a;
420                }
421            }
422        }
423        return false;
424    }
425
426    /**
427     * Add contents to this tag.
428     *
429     * There are four kinds of data in a DocBook tutorial:
430     *  1. <b>tags</b> - normal tags like <refentry>
431     *  2. <b>entities</b> - normal entities like &rdquo;
432     *  3. <b><![CDATA[</b> - character data that should not be interpreted,
433     *     like <programlisting> contents
434     *  4. <b>text</b> - normal non-markup text
435     *
436     * All four kinds of data are added here
437     *
438     * @param parserEntity|parserCData|parserXMLDocBookTag|string $el nested tag,
439     *                                                                entity, or text
440     *
441     * @return mixed
442     */
443    function add($el)
444    {
445        if (is_string($el)) {
446            return parent::add($el);
447        }
448        if (phpDocumentor_get_class($el) == 'parserxmldocbooktag') {
449            if ($el->name == 'title') {
450                $this->setTitle($el);
451            } else {
452                return parent::add($el);
453            }
454        } else {
455            return parent::add($el);
456        }
457    }
458}
459
460/**
461 * a standard entity like &rdquo;
462 *
463 * This class is designed to represent all DocBook entities.
464 *
465 * @category   ToolsAndUtilities
466 * @package    phpDocumentor
467 * @subpackage Tutorial
468 * @author     Gregory Beaver <cellog@php.net>
469 * @copyright  2002-2008 Gregory Beaver
470 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
471 * @version    Release: 1.4.4
472 * @tutorial   tutorials.pkg
473 * @link       http://www.phpdoc.org
474 * @link       http://pear.php.net/PhpDocumentor
475 * @since      1.2
476 * @todo       CS cleanup - change package to PhpDocumentor
477 * @todo       CS cleanup - change classname to PhpDocumentor_*
478 */
479class parserEntity
480{
481    /**
482     * sets up the entity
483     *
484     * @param string $name entity name
485     */
486    function parserEntity($name)
487    {
488        $this->value = $name;
489    }
490
491    /**
492     * calls the output conversion
493     *
494     * @param Converter &$c          the output converter
495     * @param bool      $postprocess if postprocessing is needed
496     *
497     * @return string
498     * @uses Converter::TranslateEntity() convert contents to text
499     * @todo CS cleanup - rename to convert for camelCase rule
500     */
501    function Convert(&$c, $postprocess = true)
502    {
503        if ($postprocess) {
504            return $c->TranslateEntity($this->value);
505        } else {
506            $trans_tbl = get_html_translation_table(HTML_ENTITIES);
507            $trans_tbl = array_flip($trans_tbl);
508            $ret       = strtr('&'.$this->value.';', $trans_tbl);
509            return $ret;
510        }
511    }
512}
513?>
514