summaryrefslogtreecommitdiff
path: root/lib/prado/framework/Web/UI/WebControls/TXmlTransform.php
blob: e3c206ffaa8682a0ea0d4e21a2e9ae103e9c1a6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<?php
/**
 * TXmlTransform class file
 *
 * @author Knut Urdalen <knut.urdalen@gmail.com>
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link https://github.com/pradosoft/prado
 * @copyright Copyright &copy; 2005-2015 The PRADO Group
 * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
 * @package System.Web.UI.WebControls
 */

/**
 * TXmlTransform class
 *
 * TXmlTransform uses the PHP's XSL extension to perform
 * {@link http://www.w3.org/TR/xslt XSL transformations} using the
 * {@link http://xmlsoft.org/XSLT/ libxslt library}.
 *
 * To associate an XML style sheet with TXmlTransform set the
 * {@link setTransformPath TransformPath} property to the namespace or path to the style sheet
 * or set the {@link setTransformContent TransformContent} property to the XML style sheet
 * data as a string.
 *
 * To associate the XML data to be transformed set the {@link setDocumentPath DocumentPath}
 * property to the namespace or path to the XML document or set the
 * {@link setDocumentContent DocumentContent} property to the XML data as a string.
 *
 * To add additional parameters to the transformation process you can use the {@link getParameters Parameters}
 * property.
 *
 * @author Knut Urdalen <knut.urdalen@gmail.com>
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package System.Web.UI.WebControls
 * @since 3.1
 */
class TXmlTransform extends TControl {

  const EXT_XML_FILE = '.xml';
  const EXT_XSL_FILE = '.xsl';

  /**
   * Constructor
   *
   * Initializes the TXmlTransform object and ensure that the XSL extension is available
   * @throws TConfigurationException If XSL extension is not available
   */
  public function __construct() {
    if(!class_exists('XSLTProcessor', false)) {
      throw new TConfigurationException('xmltransform_xslextension_required');
    }
  }

  /**
   * @return string The path to the XML style sheet.
   */
  public function getTransformPath() {
    return $this->getViewState('TransformPath', '');
  }

  /**
   * @param string The path to the XML style sheet.  It must be in namespace format.
   */
  public function setTransformPath($value) {
    if(!is_file($value)) {
      $value = Prado::getPathOfNamespace($value, self::EXT_XSL_FILE);
      if($value === null) {
	throw new TInvalidDataValueException('xmltransform_transformpath_invalid', $value);
      }
    }
    $this->setViewState('TransformPath', $value, '');
  }

  /**
   * @return string XML style sheet as string
   */
  public function getTransformContent() {
    return $this->getViewState('TransformContent', '');
  }

  /**
   * @param string $value XML style sheet as string
   */
  public function setTransformContent($value) {
    $this->setViewState('TransformContent', $value, '');
  }

  /**
   * @return string The path to the XML document. It must be in namespace format.
   */
  public function getDocumentPath() {
    return $this->getViewState('DocumentPath', '');
  }

  /**
   * @param string Namespace or path to XML document
   * @throws TInvalidDataValueException
   */
  public function setDocumentPath($value) {
    if(!is_file($value)) {
      $value = Prado::getPathOfNamespace($value, self::EXT_XML_FILE);
      if($value === null) {
	throw new TInvalidDataValueException('xmltransform_documentpath_invalid', $value);
      }
    }
    $this->setViewState('DocumentPath', $value, '');
  }

  /**
   * @return string XML data
   */
  public function getDocumentContent() {
    return $this->getViewState('DocumentContent', '');
  }

  /**
   * @param string $value XML data. If not empty, it takes precedence over {@link setDocumentPath DocumentPath}.
   */
  public function setDocumentContent($value) {
    $this->setViewState('DocumentContent', $value, '');
  }

  /**
   * Returns the list of parameters to be applied to the transform.
   * @return TAttributeCollection the list of custom parameters
   */
  public function getParameters() {
    if($params = $this->getViewState('Parameters',null)) {
      return $params;
    } else {
      $params = new TAttributeCollection();
      $this->setViewState('Parameters', $params, null);
      return $params;
    }
  }

  private function getTransformXmlDocument() {
    if(($content = $this->getTransformContent()) !== '') {
      $document = new DOMDocument();
      $document->loadXML($content);
      return $document;
    } else if(($path = $this->getTransformPath()) !== '') {
      $document = new DOMDocument();
      $document->load($path);
      return $document;
    } else {
      throw new TConfigurationException('xmltransform_transform_required');
    }
  }

  private function getSourceXmlDocument() {
    if(($content = $this->getDocumentContent()) !== '') {
      $document = new DOMDocument();
      $document->loadXML($content);
      return $document;
    } else if(($path = $this->getDocumentPath()) !== '') {
      $document = new DOMDocument();
      $document->load($path);
      return $document;
    } else {
      return null;
    }
  }

  /**
   * Performs XSL transformation and render the output.
   * @param THtmlWriter The writer used for the rendering purpose
   */
  public function render($writer) {
    if(($document=$this->getSourceXmlDocument()) === null) {
	  $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
	  parent::render($htmlWriter);
      $document = new DOMDocument();
      $document->loadXML($htmlWriter->flush());
    }
    $stylesheet = $this->getTransformXmlDocument();

    // Perform XSL transformation
    $xslt = new XSLTProcessor();
    $xslt->importStyleSheet($stylesheet);

    // Check for parameters
    $parameters = $this->getParameters();
    foreach($parameters as $name => $value) {
      $xslt->setParameter('', $name, $value);
    }
    $output = $xslt->transformToXML($document);

    // Write output
    $writer->write($output);
  }
}