Poznámka: články jsou již mnoho let staré, doba se posunula, mnoho věcí v nich doporučovaných je již dnes překonané - berte s rezervou!


PHP: Zápis XML do souboru a do těla stránky

Jazyk XML je jednoduchý, robustní proti chybám a hodí se tak k uchovávání nejrůznějších dat. Nevýhodou je, že obsahuje velké množství redundantních informací.

Zapisovat programově XML můžete dělat jednoduše pomocí funkce fwrite (do souboru) nebo echo (do stránky), ale není to příliš pohodlné ani přehledné.

Já jsem si pro tento účel napsal třídu XmlWriter, která zápis zjednoduší a zpřehlední.

Představte si například takovýto jednoduchý úsek HTML kódu (který je zároveň validní úsek kódu XML)

<html> <head> <title>Titulek</title> </head> <!-- koment --> <body bgColor="AAAAAA"> tak &lt;a&gt; se pouziva pro odkazy </body> </html>

Zapsat ho programově v PHP znamená tohle:

echo "<html>"; echo "<head>"; echo "<title>Titulek</title>"; echo "</head>"; echo "<!-- koment -->"; echo "<body bgColor=\"AAAAAA\">"; echo "tag &lt;a&gt; se pouziva pro odkazy"; echo "</body>"; echo "</html>";

Výsledek bude správný, jen nebude obsahovat odsazení a odřádkování. Přidat odřádkování je OK – stačí vypisovat odřádkovávací sekvenci – typicky "\n", ale odsazování už chce trochu víc práce.

Navíc se musíte babrat s :

  • escapováním uvozovek
  • html entitami

Já s mojí třídou můžu psát tohle:

$xml = new XMLWriter(); $xml->WriteBeginTag("html"); $xml->WriteBeginTag("head"); $xml->WriteBeginTag("title"); $xml->WriteText("Titulek"); $xml->CloseTag(); $xml->CloseTag(); $xml->WriteComment("koment"); $xml->WriteBeginTag("body"); $xml->WriteAttribute("bgColor", "AAAAAA"); $xml->WriteText("tag <a> se pouziva pro odkazy"); $xml->CloseAllTags();

A dostanu přesně stejný výstup, jako je uvedený příklad.

Navíc:

  • nemusím se starat o odsazování
  • zápis atributů je mnohem hezčí
  • pro uzavírání tagů stačí metoda CloseTag a CloseAllTags
  • entity se mi zakódují automaticky (pokud to nechci, tak stačí jeden parametr funkce WriteText navíc)

Metodou OpenFile můžete snadno přesměrovat výstup ze standartního výstupu do výstupu do souboru.

Vlastní kód je jednoduchý, jen ho prodlužují komentáře. Takhle třída vypadá:

<? /** * Class for writing XML documents into files or standart output. * Use OpenFile method to select file * In default settings class writes to standart output with * indentations of the elements * */ Class XmlWriter { private $_file; private $_sOpenedTags; private $_sTop = 0; private $_unclosedBeginTag = 0; private $_needSpace = 0; /** * Current level of indentation. * Default: 0 * * @var int */ public $Indents = 0; /** * Quotation mark used for atribute values, * Default: " * * @var string */ public $Quotation = '"'; /** * Set whether XmlWriter should indent tags in the document * to follow the hierarchical structure * Default: true * * @var bool */ public $UseIndents = 1; /** * Ending line sequence * Default: "\n" * @var string */ public $EndLine = "\n"; /** * Indent string for one level of indentation. * Default: " " * * @var string */ public $Indent = " "; /** * Enter description here... * * @var unknown_type */ public $stg; /** * Initialize the XmlWriter Class * * @param string $FileName - file to write [optional] */ public function __construct($FileName = null) { $this->OpenFile($FileName); } private function _makeSpace() { if ($this->_needSpace) echo " "; $this->_needSpace = 0; } private function _write($string) { if (!$this->_file) echo $string; else fwrite($this->_file, $string); } private function _pushTag($TagName) { $this->_sOpenedTags[$this->_sTop] = $TagName; $this->_sTop++; } private function _popTag() { $this->_sTop--; return $this->_sOpenedTags[$this->_sTop]; } private function _doIndent() { if ($this->UseIndents) { for ($i = 0; $i < $this->Indents; $i++ ) $this->_write($this->Indent); } } /** * Writes typical declaration of xml document. * For another declaration just use the FreeWrite method * * @param string $Version - XML version * @param string $Encoding - character set encoding */ public function WriteXMLDeclaration($Version = "1.0", $Encoding = "utf-8") { $this->_write("<?xml version=". $this->Quotation. $Version. $this->Quotation. " encoding=". $this->Quotation. $Encoding. $this->Quotation. "?>".$this->EndLine); } /** * Opens file with given filename for writing * Content of existing file will be lost * if no file is opened, the writer writes to standart output * * @param string $FileName - filename (can be with path) */ public function OpenFile($FileName) { if ($this->_file) fclose($this->file); $this->_file = fopen($FileName, "w"); } /** * Writes openning tag * * @param string $TagName - tag to write */ public function WriteBeginTag($TagName) { if ($this->_unclosedBeginTag) { $this->_write(">".$this->EndLine); $this->_unclosedBeginTag = 0; } $this->_doIndent(); $this->_write("<$TagName"); $this->_needspace = 1; $this->_pushTag($TagName); $this->_unclosedBeginTag = 1; $this->Indents++; $this->_needSpace = 1; } /** * Writes attribute and value for current opened tag * * @param string $Attribute - atribute name * @param string $Value - value of the atribute * @param bool $HtmlEntities - if true, text will be pre-processed before * writing to prevent cross site scripting */ public function WriteAttribute($Attribute, $Value, $HtmlEntities = 1) { if (!$this->_unclosedBeginTag) throw new Exception("XMLWriter Error: ". "Writing attribute when no tag is opened."); $this->_makeSpace(); if ($HtmlEntities) $Value = htmlentities($Value); $this->_write("$Attribute=$this->Quotation".$Value."$this->Quotation"); $this->_needSpace = 1; } /** * Writes text of the tag * * @param string $Text - text to write * @param bool $HtmlEntities - if true, text will be pre-processed before * writing to prevent cross site scripting */ public function WriteText($Text, $HtmlEntities = 1) { if ($this->_unclosedBeginTag) { $this->_write(">$this->EndLine"); $this->_unclosedBeginTag = 0; } if ($HtmlEntities) $Text = htmlentities($Text); $this->_doIndent(); $this->_write($Text.$this->EndLine); } /** * Writes closing tag for the current opened tag */ public function CloseTag() { if ($this->_unclosedBeginTag) { $this->_write("/>$this->EndLine"); $this->_unclosedBeginTag = 0; } else { $this->Indents--; $this->_doIndent(); $this->_write("</".$this->_popTag().">$this->EndLine"); } } /** * Writes string into the document without formating * * @param string $string - string to write */ public function FreeWrite($string) { $this->_write($string); } /** * Closes all currently opened tags * */ public function CloseAllTags() { while ($this->_sTop > 0) $this->CloseTag(); } /** * Writes XML comment * * @param string $Comment - Comment text */ public function WriteComment($Comment) { $this->_doIndent(); $this->_write("<!-- $Comment -->".$this->EndLine); } } $xml = new XMLWriter(); //$xml->OpenFile("out.xml"); $xml->WriteXMLDeclaration(); $xml = new XMLWriter(); $xml->WriteBeginTag("html"); $xml->WriteBeginTag("head"); $xml->WriteBeginTag("title"); $xml->WriteText("Titulek"); $xml->$xml->CloseTag(); $xml->WriteComment("koment"); $xml->WriteBeginTag("body"); $xml->WriteAttribute("bgColor", "AAAAAA"); $xml->WriteText("tag <a> se pouziva pro odkazy"); $xml->CloseAllTags(); ?>
Ohodnoťte prosím užitečnost článku




28
 
54
 
58
 
46
 
27
 
 
Vložit komentář:
 

 



 

 

Nepoužívejte žádné html ani texy značky, odřádkování se zachová. Pokud uvádíte zdrojový kód, můžete ho vložit mezi značky
<syntax jazyk="PHP">...</syntax>,
bude potom zformátován. Jako atribut můžete uvést PHP, C#, HTML, CSS a mnoho dalších.


opiste cislo Opište číslo:

 

7. 4. 2007 21:33:47
[1] (Pavel Gloss (pavel.gloss(at)post.cz)) www
XMLWriter z PHP odpovědět
Ahoj, zrovna zkouším třídu XMLWriter přímo z PHP a narazil jsem na nepříjemný problém. Při použití akcentovaných znaků jako hodnot elementů/atributů, metoda outputMemory() zkolabuje. Nemáš s tím zkušenost ?
Tak jsem nakonec narazil na tvou verzi XMLWriteru a jdu vyzkoušet.
Každopádně je ale škoda, že něco co už je připraveno v PHP, nefunguje jak má.
8. 9. 2008 10:00:08
[2] (jakub (jacobo(at)centrum.sk))
Re: XMLWriter z PHP odpovědět
[1] v deklaracia XML je spravena tak ze v nazvoch elementov a atributov sa mozu pouzivat iba ASCII znaky a to iba take co reprezentuju pisane znaky, napr. ani medzera nemoze byt v nazve elementu. je to tak koli validacii a myslim si ze pisat kod je lepsie po anglicky ako po cesky, menej problemov a vyzera to aj lepsie
29. 1. 2010 10:50:15
[3] (jmikulas (jiri(at)mikulas.com))
CloseTag() a _popTag() odpovědět
Ahoj,
Na podnet z RSS validatoru http://beta.feedvalidator.org/docs/warning/MissingAtomSelfLink.html
jsem chtel zapsat tento neparovy tag.
Narazil jsem na problem pri _unclosedBeginTag=1
podle me ve funkci CloseTag() chybi volani _popTag()
ve vysledku by to melo vypadat takhle..
public function CloseTag() { if ($this->_unclosedBeginTag) { $this->_write("/>$this->EndLine"); $this->_popTag(); $this->_unclosedBeginTag = 0; } else ......

kdyz se nevolal _popTag, tak se mi ke konci dokumentu generoval close tag </atom:link>, po pridani _popTag uz to vypada ok.
Jeste prikladam zapis toho neparoveho atom tagu
/** * http://beta.feedvalidator.org/docs/warning/MissingAtomSelfLink.html * <atom:link href="http://dallas.example.com/rss.xml" rel="self" type="application/rss+xml" /> */ $w->WriteBeginTag("atom:link"); $w->WriteAttribute("href", "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']); $w->WriteAttribute("rel", "self"); $w->WriteAttribute("type", "application/rss+xml"); $w->CloseTag();