Toon posts:

[php5][DOM] Toepassen van DOM in eigen HTMLLayer

Pagina: 1
Acties:

Verwijderd

Topicstarter
Beste mensen,

Ik ben nu ff een paar uurtjes bezig met het maken van een eigen HTML layer en dat lukt best goed alleen zit ik met 1 probleempje. Ik wil dat de code die DOM voor me genereerd XHTML conform is, alleen dit lukt me niet helemaal.

Gelieve geen reacties over dat ik tever wil gaan met PHP, of het geen nut heeft, het tweede wiel uitgevonden wordt of iets dergelijks want ik zie de voordelen in de context waarin ik de applicatie in maak er wel van in.

Maargoed het probleem is dat dat ik wil dat bijvoorbeeld HTML elementen zoals <input> selfclosing zijn i.v.m het genereren van XHTML code. Echter als ik de methode saveXML() gebruik dan maakt hij ze wel selfclosing maar uiteraard krijg je dit wel elke keer:

code:
1
<?xml version="1.0" encoding="iso-8859-1"?>


Dit is niet de bedoeling omdat ik deze objecten gebruik om stukjes html te genereren. Ook als ik de DOMImplementation gebruik met de w3c doctype werkt het niet vaag genoeg, dan alsnog maakt hij tags zoals "input" niet selfclosing.

Mijn vraag is dan ook, is het mogelijk om XHTML te genereren vanuit DOM die dus W3C compliant is en dat hij niet elke keer het doctype print? Of gebruik ik het nu op een foute manier?

Mijn code tot nu toe:
PHP:
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
194
195
196
197
<?php
/*
  $Id: class.select.php,v 1.0 2006/07/07 22:10:38 hpdl Exp $

  Author: Kees Schepers  
  More Info: http://www.phphulp.nl/php/scripts/4/692
  Released under the GNU General Public License
*/
interface htmlElementInterface {
      /**
      * Function which builds the select box and gives you back the HTML
      **/
      public function getHTML();
      /**
      * Get the whole object with a tree construction to add this object to others
      **/      
      public function getDomObject();
}
abstract class htmlElement {
      protected $aAttributes;
      protected $objDomDocument;
      protected $allowedAttributes;
      public function __Construct() {
            /**
            * Start the DOM document for creating HTML
            **/
            $this->objDomDocument = new DOMDocument('1.0','iso-8859-1');                        
            
            $this->allowedAttributes = array();
            $this->allowedAttributes[]='id';
      }
      public function __Set($key,$value) {
            if( in_array($key,$this->allowedAttributes) ) {
                  $this->aAttributes[$key] = $value;
            } else {
                  throw new exception('htmlElement::__Set -> attribute: '.$key.' not allowed in current HTML element!');
            }
      }      
      /**
      * function which adds attributes to the select element.
      **/
      protected function setAttributes($htmlObject) {
            if( is_array($this->aAttributes) ) {
                  foreach($this->aAttributes AS $attributeName=>$attributeValue) {
                        $htmlObject->setAttribute($attributeName,$attributeValue);
                  }
            }
      }      
}
/**
* Class to create a select box and to set some property's
**/
class select extends htmlElement implements htmlElementInterface {            
      private $aData;
      private $objSelect; 
      private $sDefaultValue;     
      public function __Construct($p_aData) { 
            parent::__Construct();           
            /**
            * Check and build the data array
            **/
            $this->aData = array();
            $this->setData($p_aData);
            
            $this->allowedAttributes[]='name';
            $this->allowedAttributes[]='onchange';
            $this->allowedAttributes[]='style';
            $this->allowedAttributes[]='class';            
            
      }
      public function setDefaultValue($p_sValue) {
            $this->sDefaultValue = $p_sValue;
      }      
      /**
      * function which builds the correct data array which will be internaly used.
      * @param array $p_aData array with elements for the select list
      **/
      private function setData($p_aData) {
            if( is_array($p_aData) ) {
                  foreach($p_aData AS $element) {
                        if( is_array( $element ) ) {
                              if( count( $element ) > 1 )  {
                                    /**
                                    * Array has a value and a text node. The first index is the value second the                                     
                                    * text node. If more keys given, ignore them.
                                    **/
                                    $this->aData[] = array('value' => $element[0],'text' => $element[1]);
                              } else {
                                    throw new exception('select::setData() -> Wrong data given as parameter! (expects an array with at least more then one index)');
                              }
                        } else {
                              /**
                              * Text and value are the same
                              **/
                              $this->aData[] = array('value' => $element, 'text' => $element);
                        }
                  }
            } else {
                  throw new exception('select::setData() -> Data given as parameter should be an array!');
            }
      }
      /**
      * function which creates the select element, and calls the attribute(s)-creator-function
      **/
      private function setSelectElement() {
            $this->objSelect = $this->objDomDocument->createElement('select');
            $this->objSelect = $this->objDomDocument->appendChild($this->objSelect);
            $this->setAttributes($this->objSelect);
      }
      /**
      * This function loops the array and creates the select box options
      **/
      private function setSelectOptions() {
            if( is_array($this->aData) ) {
                  /**
                  * Loop all array options
                  **/
                  foreach($this->aData AS $aElement) {
                        $objOption = $this->objDomDocument->createElement('option');
                        $objOption = $this->objSelect->appendChild($objOption);
                        $objOption->setAttribute('value',$aElement['value']);
                        if( $aElement['value'] == $this->sDefaultValue ) {
                              if( !$objOption->hasAttribute('selected') ) {
                                    $objOption->setAttribute('selected','selected');
                              }
                        }
                        $objOptionText = $this->objDomDocument->createTextNode($aElement['text']);
                        $objOptionText = $objOption->appendChild($objOptionText);                        
                  }
            } else {
                  throw new exception('select::getSelectedOption() -> No data given in object!');
            }
      }
      /**
      * Calls all his members to actually create his select box
      **/
      private function createSelectBox() {
            $this->setSelectElement();
            $this->setSelectOptions();
      }
      public function getDomObject() {
            $this->createSelectBox();
            return $this->objDomDocument;
      }
      public function getHTML() {
            $this->createSelectBox();
            return $this->objDomDocument->saveHTML();
      }
}
class input extends htmlElement implements htmlElementInterface {
      private $objInput;
      /**
      * Constructor
      * @param string $p_sInputType the type off input element (password,text,radio,checkbox etc)
      **/
      function __Construct($p_sInputType) {
            parent::__Construct();  
            /**
            * Set the optional attributes of this HTML element
            **/
            $this->allowedAttributes[]='name';            
            $this->allowedAttributes[]='type';
            $this->allowedAttributes[]='class';
            $this->allowedAttribures[]='style';
            
            /**
            * The input type is a mandatory attribute
            **/
            $this->__Set('type',$p_sInputType);
            
      }
      function setInputElement() {
            $this->objInput = $this->objDomDocument->createElement('input');
            $this->objInput = $this->objDomDocument->appendChild($this->objInput);
            $this->setAttributes($this->objInput);
      }
      public function getDomObject() {
            $this->setInputElement();
            return $this->objDomDocument;
      }
      public function getHTML() {
            $this->setInputElement();
            return $this->objDomDocument->saveHTML();
      }
}

$selectBox = new select(array('test1','test2','test3','test4'));
$selectBox->id = 'selectBox1';
$selectBox->onchange = 'alert(this.value);';
$selectBox->setDefaultValue('test3');
echo $selectBox->getHTML();

$input = new input('text');
$input->name = 'textField';
$input->id = 'input1';
echo $input->getHTML();
?>


Genereerd:
code:
1
2
3
4
5
<select id="selectBox1" onchange="alert(this.value);"><option value="test1">test1</option>
<option value="test2">test2</option>
<option value="test3" selected>test3</option>
<option value="test4">test4</option></select>
<input type="text" name="textField" id="input1">

Verwijderd

Waarom wil je geen "processing instruction"? Dat is toch een normale instructie voor een xhtml document... (okee IE vind het niet lief, maar die krijg je zonder dtd hacks toch niet in strict modus)

Verwijderd

Verwijderd schreef op vrijdag 07 juli 2006 @ 23:49:
Mijn vraag is dan ook, is het mogelijk om XHTML te genereren vanuit DOM die dus W3C compliant is en dat hij niet elke keer het doctype print? Of gebruik ik het nu op een foute manier?
Wat jij nodig hebt is het xsl:output-element. In dit element kun je onder andere aangeven of (en zo ja, welk) doctype moet worden weergegeven. Ook de XML-declaratie kun je hiermee in- en uitschakelen.

Uitleg over xsl:output kun je vinden op deze pagina van w3Schools. Onderstaande code gebruik ik zelf om de output van de XSLT-processor te sturen.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Loading the XSL stylesheet
$XSL = DOMDocument::load($XSLPath);

// Setting the xsl:output element to control the XSLT processor output
$nodeOutput = $XSL->createElementNS('http://www.w3.org/1999/XSL/Transform', 'xsl:output');
$nodeOutput->setAttribute('omit-xml-declaration', 'no');
$nodeOutput->setAttribute('encoding', 'UTF-8');
$nodeOutput->setAttribute('indent', 'yes');
$nodeOutput->setAttribute('method', 'xml');
$nodeOutput->setAttribute('doctype-public', '-//W3C//DTD XHTML 1.0 Strict//EN');
$nodeOutput->setAttribute('doctype-system', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');

// Adding the xsl:output element to the xsl:stylesheet element
$stylesheet = $XSL->getElementsByTagName('stylesheet');
$stylesheet->item(0)->appendChild($nodeOutput);

Het genereren van W3C compliant code komt overigens geheel voor rekening van de programmeur ;) .

Verwijderd

Topicstarter
Verwijderd schreef op zaterdag 08 juli 2006 @ 12:35:
[...]

Wat jij nodig hebt is het xsl:output-element. In dit element kun je onder andere aangeven of (en zo ja, welk) doctype moet worden weergegeven. Ook de XML-declaratie kun je hiermee in- en uitschakelen.

Uitleg over xsl:output kun je vinden op deze pagina van w3Schools. Onderstaande code gebruik ik zelf om de output van de XSLT-processor te sturen.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Loading the XSL stylesheet
$XSL = DOMDocument::load($XSLPath);

// Setting the xsl:output element to control the XSLT processor output
$nodeOutput = $XSL->createElementNS('http://www.w3.org/1999/XSL/Transform', 'xsl:output');
$nodeOutput->setAttribute('omit-xml-declaration', 'no');
$nodeOutput->setAttribute('encoding', 'UTF-8');
$nodeOutput->setAttribute('indent', 'yes');
$nodeOutput->setAttribute('method', 'xml');
$nodeOutput->setAttribute('doctype-public', '-//W3C//DTD XHTML 1.0 Strict//EN');
$nodeOutput->setAttribute('doctype-system', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');

// Adding the xsl:output element to the xsl:stylesheet element
$stylesheet = $XSL->getElementsByTagName('stylesheet');
$stylesheet->item(0)->appendChild($nodeOutput);

Het genereren van W3C compliant code komt overigens geheel voor rekening van de programmeur ;) .
Interessant, ik heb nog nooit iets met XSL gedaan maar het blijkt een soort "template" parser te zijn voor XML ? Dat betekend dus dat ik eigenlijk dat ik een XSL template moet maken voor mijn HTMLLayer/tags?

Inprinciepe wil het doctype wel printen maar niet bij elk HTML element wat ik maak, vandaar dat ik met dit probleem zit. Echter zeg je ook het genereren van W3C compliant code is voor de programmeur, maar dat hangt er dan dus vanaf hoe jij je XSL template inricht? Want daar luisterd je DOM naar?

Bedankt voor het reageren en ook de bovenstaande.

  • Dennis
  • Registratie: Februari 2001
  • Laatst online: 14-02 23:16
Met xsl kun je een xml document 'converteren' naar een xhtml document. Ik begrijp je vraag niet helemaal, maar het is misschien interessant om te weten dat je zelfs clientside je xml kunt parsen. Ondersteuning daarvoor zit al in een aantal browsers ingebakken.

Verwijderd

XSL lijkt mij in dit geheel vrij nutteloos. Je introduceert een extra overbodige vertaal slag. Je kunt toch direct naar xhtml vertalen ipv een tussenstap via xml. Xsl valt bijna nooit te rechtvaardigen, enkel bij externe (3rd party) xml heeft het zijn nut.

En om maar even te voorkomen dat iemand het argument "template" aan gaat dragen voor xsl: je php page is al je template.

Dus voor zaken als het wel of niet toevoegen van processing instructions aan de out stream zou je gewoon bij je parser moeten zijn. Het is vast een instelling. Maar probeer eerst eens duidelijk op een rijtje te krijgen wat je nu daadwerkelijk naar buiten wil hebben.

Onderstaande is namelijk een volledig correct fragment van xhtml. Alleen dit gaat in IE(6) niet werken (als in dat deze strict modus draait) maar dat is totaal te negeren want dat krijg je enkel voor elkaar met hacks aan de dtd.

code:
1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

Verwijderd

Verwijderd schreef op zondag 09 juli 2006 @ 10:29:
XSL lijkt mij in dit geheel vrij nutteloos. Je introduceert een extra overbodige vertaal slag. Je kunt toch direct naar xhtml vertalen ipv een tussenstap via xml.
Ik ging - zonder de code door te spitten - ervan uit dat de TS al met XSLT werkte. Dat blijkt dus niet zo te zijn. Dan is XSLT inderdaad een "dure" tussenstap. Maar of het overbodig is?
Verwijderd schreef op zondag 09 juli 2006 @ 10:29:
Xsl valt bijna nooit te rechtvaardigen, enkel bij externe (3rd party) xml heeft het zijn nut.
Hhmm, ik vind het toch wel erg handig. Het geeft soms een hoop gedoe, maar ik kan er toch prima mee leven. Ik heb eens een (min of meer commerciële) boekhoudapplicatie ontwikkelt met de XML/XSLT-tussenlaag. En dat werkte als een trein! Het is handig als je in je php niet continue met HTML aan de slag hoeft. Hoewel, als je aparte templates in php maakt waarin je _alleen_ maar je var's en array's laat zien moet dat ook wel uit elkaar te houden zijn. De reden dat ik toch voor de XML/XSLT-tussenlaag kies is dat ik hiermee gelijk een uiterst bruikbare XML-stream heb die ik in geval van koppeling met andere programma's zonder verdere aanpassing kan aanbieden. Voor websites meestal niet interessant, maar voor webapplicaties soms een uitkomst :*).

Verwijderd

Topicstarter
Verwijderd schreef op zondag 09 juli 2006 @ 10:29:
XSL lijkt mij in dit geheel vrij nutteloos. Je introduceert een extra overbodige vertaal slag. Je kunt toch direct naar xhtml vertalen ipv een tussenstap via xml. Xsl valt bijna nooit te rechtvaardigen, enkel bij externe (3rd party) xml heeft het zijn nut.

En om maar even te voorkomen dat iemand het argument "template" aan gaat dragen voor xsl: je php page is al je template.

Dus voor zaken als het wel of niet toevoegen van processing instructions aan de out stream zou je gewoon bij je parser moeten zijn. Het is vast een instelling. Maar probeer eerst eens duidelijk op een rijtje te krijgen wat je nu daadwerkelijk naar buiten wil hebben.

Onderstaande is namelijk een volledig correct fragment van xhtml. Alleen dit gaat in IE(6) niet werken (als in dat deze strict modus draait) maar dat is totaal te negeren want dat krijg je enkel voor elkaar met hacks aan de dtd.

code:
1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
Ik heb al op een rijtje wat ik naar buiten wil krijgen, en dat zijn HTML tags d.m.v. mijn klassen met behulp van DOM. Daar docht ik dus mee dynamisch HTML mee te kunnen genereren.

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Ik ben ook wel fan van de XSLT-aanpak. Je kunt daardoor een extra ontkoppeling aanbrengen in je code, die dan nog slechts een model-achtig soort XML produceert. Later kun je daar door middel van transformaties weer andere formaten mee bouwen. Meestal zal dat wel XHTML zijn, maar het zou bijvoorbeeld ook een RSS/Atom-feed kunnen zijn, of een stuk XSL-FO (dat heb ik laatst een keer gebruikt).

Rustacean


Verwijderd

Wat dacht je van
public function getHTML() {
$this->setInputElement();
return $this->objDomDocument->saveXML($this->objInput);
}
Door $this->objInput als argument mee te gevenvoorkom je dat de doctype wordt gegenereerd.

Verwijderd

Topicstarter
Super bedankt! Ik las dankzij een collega jouw opmerking heel laat, meteen getest en inderdaad het werkt! :D nu nog even een singleton maken van de domdocument class..

tnx!
Pagina: 1