22
تشکر

DOMDocument در PHP

DOM

DOM

کلاس DOMDocument در PHP کاربردهای سودمندی از جمله خواندن و نوشتن در فایل های xml و html را دارد. با کمک آن می توان فایل های xml و html را باز کرد و اطلاعات آن را پارس کرد.

در ادامه به بررسی سطحی و موردی کار با بخشی از امکانات این کتابخانه می پردازیم. جهت اطلاع بیشتر می توانید به مستندات کامل و دقیقی که پیرامون این موضوع در php.net موجود است مراجعه کنید.

ایجاد فایل xml

<?xml version="1.0" encoding="ISO-8859-15"?>
<Album>
	<Track length="0:01:15" bitrate="64kb/s" channels="2">
		The ninth symphony
		<Note>The last symphony composed by Ludwig van Beethoven.</Note>
	</Track>
	<Track channels="2">Highway Blues</Track>
</Album>

به طور مثال برای ساخت فایل xml بالا باید کدهای زیر را نوشت :

<?php

// "Create" the document.
$xml = new DOMDocument( "1.0", "ISO-8859-15" );

// Create some elements.
$xml_album = $xml->createElement( "Album" );
$xml_track = $xml->createElement( "Track", "The ninth symphony" );

// Set the attributes.
$xml_track->setAttribute( "length", "0:01:15" );
$xml_track->setAttribute( "bitrate", "64kb/s" );
$xml_track->setAttribute( "channels", "2" );

// Create another element, just to show you can add any (realistic to computer) number of sublevels.
$xml_note = $xml->createElement( "Note", "The last symphony composed by Ludwig van Beethoven." );

// Append the whole bunch.
$xml_track->appendChild( $xml_note );
$xml_album->appendChild( $xml_track );

// Repeat the above with some different values..
$xml_track = $xml->createElement( "Track", "Highway Blues" );

$xml_track->setAttribute( "channels", "2" );
$xml_album->appendChild( $xml_track );

$xml->appendChild( $xml_album );

// Parse the XML.
$output = $xml->saveXML();
echo $output;
// Save in xml file 
$xml->save('filename.xml');

در کد بالا، ابتدا یک شی از DOMDocument ایجاد کردیم. سپس با متد createElement این کلاس، یک شی از نوع DOMElement ایجاد شد. آرگومان اول createElement، نام تگ و آرگومان دوم مقدار تگ است. متد setAttribute برای اختصاص دادن خصوصیات به تگ مربوطه است .

متد appendChild برای افزودن یک زیر مولفه جدید است. همانطور که در بالا ملاحظه کردید عنصر Note داخل عنصر Track قرارگرفته بنابراین بایستی از متد appendChild استفاده کرد.

در آخر هم با متد saveXML شی DOMDocument می توانید به محتوای xml تولید شده دسترسی داشته باشید و یا اگر خواستید با متد save آنرا به صورت یک فایل xml ذخیره کنید.

پیمایش فایل xml

فرض می کنیم فایل xml زیر را داریم و می خواهیم آنرا در یک آرایه PHP کپی کنیم.

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
   </book>
   <book id="bk103">
      <author>Corets, Eva</author>
      <title>Maeve Ascendant</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-11-17</publish_date>
   </book>
</catalog>
<?php

$dom = new DOMDocument();
$dom->load('test.xml');

$items = $dom->getElementsByTagName('book') ;
foreach($items as $item) {
	if($item->childNodes->length) {
		foreach($item->childNodes as $i) {
			$headline[$i->nodeName] = $i->nodeValue;
		}
	}
	$headlines[] = $headline;
} 
foreach($headlines as $headline) {
	echo $headline['title'] . "<br>";
}

از طریق متد getElementsByTagName به عنصری با نام مشخص شده دسترسی خواهیم داشت. سپس همه نودهای فرزند book را که به عبارتی مشخصات کتاب ها می شوند را با یک حلقه پیمایش کردیم و در یک آرایه ریختیم و در آخر هم عنوان همه کتاب ها را چاپ کردیم.

ویرایش و حذف در فایل xml

حالا در آخرین مثال از کار با xml می خواهیم فایل xml کتاب ها، در مثال قبل را ویرایش کنیم به طوریکه قیمت یک کتاب، با عنوان مشخص را تغییر دهیم. علاوه براین آرایه‌ای از کتاب‌هایی که نویسنده مشخصی را دارند را ایجاد و آنها را با دستور removeChild حذف کنیم.

<?php

$dom=new DOMDocument();
$dom->load("test.xml");

// This can differ (I am not sure, it can be only documentElement or documentElement->firstChild or only firstChild)
$root = $dom->documentElement;

$nodesToDelete = array();

$books = $root->getElementsByTagName('book');

// Loop trough childNodes
foreach ($books as $book) {
	$author = $book->getElementsByTagName('author')->item(0)->textContent;
	$title = $book->getElementsByTagName('title')->item(0)->textContent;
	$genre = $book->getElementsByTagName('genre')->item(0)->textContent;
	$price = $book->getElementsByTagName('price')->item(0)->textContent;
	$publish_date = $book->getElementsByTagName('publish_date')->item(0)->textContent;

	// To remove the book you just add it to a list of nodes to delete
	if ($author == 'Gambardella, Matthew')
	{
		$nodesToDelete[] = $book;
	}
	// To edit the book you should assignment 
	if ($title == 'Maeve Ascendant')
	{
		$book->getElementsByTagName('price')->item(0)->nodeValue = '6.50';
	}
}

// You delete the nodes
foreach ($nodesToDelete as $node) $node->parentNode->removeChild($node);

// for save in file
$dom->save('test.xml');

// for save in file
echo $dom->saveXML();

همانطور که میدانید برای حذف یک عنصر باید در یک شاخه بالاتر قراربگیرید (با دستور parentNode) سپس شاخه فرزند را از بین ببرید.

نکته: ایجاد آرایه برای حذف اختیاری می باشد. در غیر اینصورت می‌توانید داخل حلقه از کد زیر استفاده کنید.

if ($author == 'Gambardella, Matthew') {
    $book->parentNode->removeChild($book);
}

ایجاد فایل html

برای کار با html، کدها تفاوت زیادی با قبل ندارند. شما می‌توانید با کمی خلاقیت یک کلاس ایجاد کنید تا متدهای آن برای شما عنصرهای html را ایجاد کنند.
مثلا در مثال زیر متدی برای ایجاد تگ select داریم:

<?php 
class BuildHtml
{
	public static function select($attributes)
	{
		$dom = new \DOMDocument('1.0');
		$select = $dom->createElement('select');
		foreach ($attributes as $key => $value) {
			if($key == 'options') continue;
			$selectAttribute = $dom->createAttribute($key);
			$selectAttribute->value = $value;
			$select->appendChild($selectAttribute);
		}
		
		//Add options to select box
		if (isset($attributes['options'])) {    
			foreach ($attributes['options'] as $option => $value) {
				$option = $dom->createElement('option', $option);
				$optionAttribute = $dom->createAttribute('value');
				$optionAttribute->value = $value;
				$option->appendChild($optionAttribute);
				$select->appendChild($option);
			}
		}
		return $dom->saveHTML($select);        
	}
}

echo BuildHtml::select(array(
	'name' => 'age_range',
	'class' => 'my-select',
	'options' => array(
		'child' => 'child',
		'Teenager' => 'Teenager',
		'Middle_age' => 'Middle age'
	),
	));

در نمونه زیر یک فایل ساخته شده با DOMDocument را می بینید.

<?php

$dom = new DOMDocument('1.0');//Create new document

//Create the CSS styles
$css_text = '';
$css_text .= 'body{width:285px;margin:auto;margin-top:50px;}';
$css_text .= '#my_table{border:1px solid #ececec;}';
$css_text .= '#my_table th{border:1px solid #ececec;padding:5px;text-decoration:underline;}';
$css_text .= '#my_table td{border:1px solid #ececec;padding:5px;}';
$css_text .= '#my_table td:first-child{text-align:right;color:#333333;font-weight:bold;color:#999999;}';

$style = $dom->createElement('style', $css_text);//Create new <style> tag with the css tags

$domAttribute = $dom->createAttribute('type');//Create the new attribute

$domAttribute->value = 'text/css';//Add value to attribute

$style->appendChild($domAttribute);//Add the attribute to the style tag

$dom->appendChild($style);//Add the style tag to document

//Add the form
$form = $dom->createElement('form');
$dom->appendChild($form);
$formAttribute = $dom->createAttribute('method');
$formAttribute->value = 'post';
$form->appendChild($formAttribute);

//Add the table
$table = $dom->createElement('table');
$tableAttribute = $dom->createAttribute('id');
$tableAttribute->value = 'my_table';
$table->appendChild($tableAttribute);

//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$th = $dom->createElement('th', 'Generate HTML using PHP');
$tr->appendChild($th);
$thAttribute = $dom->createAttribute('colspan');
$thAttribute->value = '2';
$th->appendChild($thAttribute);


//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$td = $dom->createElement('td', 'First Name');
$tr->appendChild($td);

//Add new column
$td = $dom->createElement('td');
$tr->appendChild($td);

//Add input element to column
$input = $dom->createElement('input');
$td->appendChild($input);
$tdAttribute = $dom->createAttribute('type');
$tdAttribute->value = 'text';
$input->appendChild($tdAttribute);
$tdAttribute = $dom->createAttribute('name');
$tdAttribute->value = 'f_name';
$input->appendChild($tdAttribute);

//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$td = $dom->createElement('td', 'Email');
$tr->appendChild($td);

//Add new column
$td = $dom->createElement('td');
$tr->appendChild($td);

//Add input element to column
$input = $dom->createElement('input');
$td->appendChild($input);
$tdAttribute = $dom->createAttribute('type');
$tdAttribute->value = 'text';
$input->appendChild($tdAttribute);
$tdAttribute = $dom->createAttribute('name');
$tdAttribute->value = 'e-mail';
$input->appendChild($tdAttribute);

//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$td = $dom->createElement('td', 'Gender');
$tr->appendChild($td);

//Add new column
$td = $dom->createElement('td');
$tr->appendChild($td);

//Add input element to column
$select = $dom->createElement('select');
$td->appendChild($select);
$tdAttribute = $dom->createAttribute('name');
$tdAttribute->value = 'gender';
$select->appendChild($tdAttribute);
//Add options to select box
$opt = $dom->createElement('option', 'Male');
$domAttribute = $dom->createAttribute('value');
$domAttribute->value = 'male';
$opt->appendChild($domAttribute);
$select->appendChild($opt);

$opt = $dom->createElement('option', 'Female');
$domAttribute = $dom->createAttribute('value');
$domAttribute->value = 'female';
$opt->appendChild($domAttribute);
$select->appendChild($opt);


//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$td = $dom->createElement('td', 'Interest');
$tr->appendChild($td);

//Add new column
$td = $dom->createElement('td');
$tr->appendChild($td);

//Add input element to column
$radio = $dom->createElement('input');
$td->appendChild($radio);
$radAttribute = $dom->createAttribute('type');
$radAttribute->value = 'radio';
$radio->appendChild($radAttribute);
$radAttribute = $dom->createAttribute('name');
$radAttribute->value = 'interest';
$radio->appendChild($radAttribute);
$radAttribute = $dom->createAttribute('id');
$radAttribute->value = 'php';
$radio->appendChild($radAttribute);

$label = $dom->createElement('label', 'PHP');
$labelAttribute = $dom->createAttribute('for');
$labelAttribute->value = 'php';
$label->appendChild($labelAttribute);
$td->appendChild($label);

$radio = $dom->createElement('input');
$td->appendChild($radio);
$radAttribute = $dom->createAttribute('type');
$radAttribute->value = 'radio';
$radio->appendChild($radAttribute);
$radAttribute = $dom->createAttribute('name');
$radAttribute->value = 'interest';
$radio->appendChild($radAttribute);
$radAttribute = $dom->createAttribute('id');
$radAttribute->value = 'jquery';
$radio->appendChild($radAttribute);

$label = $dom->createElement('label', 'jQuery');
$labelAttribute = $dom->createAttribute('for');
$labelAttribute->value = 'jquery';
$label->appendChild($labelAttribute);
$td->appendChild($label);

//Add new row
$tr = $dom->createElement('tr');
$table->appendChild($tr);

//Add new column
$td = $dom->createElement('td');
$tr->appendChild($td);
$tdAttribute = $dom->createAttribute('colspan');
$tdAttribute->value = '2';
$td->appendChild($tdAttribute);

//Add input element to column
$input = $dom->createElement('input');
$td->appendChild($input);
$tdAttribute = $dom->createAttribute('type');
$tdAttribute->value = 'submit';
$input->appendChild($tdAttribute);
$tdAttribute = $dom->createAttribute('value');
$tdAttribute->value = 'Sign-Up';
$input->appendChild($tdAttribute);


//Add table to form
$form->appendChild($table);

echo $dom->saveHTML();
  • محمود می‌گه:

    ممنون بابت مطالبتون

    دوستان توجه داشته باشند که برای کارهای سنگین (کارهایی که هزاران کاربر ممکن است با اسکریپت کار کنند) استفاده از چنین کلاسهایی مثل DOM
    منابع سرور رو به شدت مصرف میکنه و اگر کارتون با یه REGEX راه میفته بهتره با همون کار کنید تا پرفورمنس بالاتری داشته باشید :)
    موفق باشید

  • متین می‌گه:

    عالی بود!!
    همین چند روز پیش بود که میخواستم یه فایل html پارس کنم که دنبال همچین مطلبی بودم ( البته کارم با regex راه افتاد)
    دم شما گرم
    😉

  • فرهاد قائمی می‌گه:

    بابا دمت گرم چند وقت بود دنبال این مطلب میگشتم. واقعا مشکلم رو حل کردی ممنون ازت.

  • آروین می‌گه:

    سلام آقا آرمان عالی بود… من نصف عمرمو دنبال این مطلب بودم و حتی تو سایت های خارجی هم موفق به پیدا کردنش نشدم. الآن باورم نمیشه بالاخره پیداش کردم!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  • saeedvir می‌گه:

    ممنون.دنبال این مطلب بودم.

  • محسن شفیعی می‌گه:

    عالی بود. ممنون


  • نظرات این مطلب بسته است.