В связи с появлением в парсере возможности работать с внешними файлами (не на локальном сервере), появилась возможность получать и выводить информацию из внешних источников у себя на сайте.

В этом примере я рассмотрю использование внешнего XML файла с анонсами материалов, для опубликования ссылок на эти материалы у себя на сайте. Сделаю это на примере сайта php в деталях. Содержимое и структуру XML этого файла смотрите по адресу, который найдете в нижеприведённом коде.

Небольшое предостережение — если XML файл расположен на сервере с русским Apache, нужно обязательно отключить перекодировку с его помощью, иначе может возникнуть ситуация с несовпадением реальной и кодировки в XML декларации. Ну и теперь к делу, — код выглядит следующим образом:

#######
# формирование анонсов последних материалов
# с сайта php в деталях
# Блок <ul>...</ul> написал Константин Томашевич (konst@design.ru)
@phpdetails[][src;local_file;xml;list;now]
# определяем локальный файл где находится XML
$local_file[/phpdetails/last10.xml]

# проверяем локальный файл, - если его дата изменения более чем на
# день старее текущего времени, грузим его с внешнего сервера
$src[^file::stat[$local_file]]
$now[^date::now[]]
^if($src.mdate < $now-1){

# пытаемся загрузить внешний XML файл и сохранить его
# если не удается загрузка, обрабатываем исключение и ничего не делаем
	^try{
		$src[^file::load[text;http://detail.phpclub.net/last10.xml]]
		^src.save[text;$local_file]
	}{
		$exception.handled(1)
	}
}

# всегда создаем объект класса xdoc из XML файла на локальном диске
# разумеется он должен всегда существовать. При удачной загрузке с
# внешнего сервера, он ещё и постоянно обновляется
$xml[^xdoc::load[$local_file]]

# хэш элементов(анонсов) из файла, нужен для определения количества анонсов
$list[^xml.select[/last/item]]

<ul>
#!*!# нумерациЯ с 0 (исправлен range в if)
^for[i](0;$list-1){
#!*!# нет смысла делать еще раз selectXXX, ибо мы уже в цикле типа xsl:for-each
#!*!# более того, если не проверЯешь наличие аттрибутов, можно сократить до
#!*!# одной строки - $list == hash of xnode (/last/item)
	<li>
		^list.[$i].getAttribute[date]
		<a href="http://detail.phpclub.net/^list.[$i].getAttribute[dir]^list.[$i].getAttribute[file].htm">
			^list.[$i].getAttribute[title]
		</a>
	</li>
	
}
</ul>

Немного комментариев.

  1. Работа по вытягиванию информации из XML всегда ведется с локальным файлом.
  2. Раз в сутки проверяется дата изменения локального файла и если она более чем на сутки старее текущий производится загрузка внешнего файла.
  3. Здесь сделано предположение, что, внешний файл меняется раз в сутки, если это не так и файл меняется гораздо реже, стоит этот период увеличить.

Пусть вас не удивляют странные комментарии сделанные между тегами ul — первоначальный вариант кода был такой:

<ul>
^for[i](1;$list){ 
	$date{^xml.selectString[string(/last/item[position() = $i]/@date)]} 
	$title{^xml.selectString[string(/last/item[position() = $i]/@title)]} 
	$path{^xml.selectString[string(/last/item[position() = $i]/@dir)]} 
	$file{^xml.selectString[string(/last/item[position() = $i]/@file)]} 
	<li>$date <a href="http://detail.phpclub.net/${path}${file}.htm">$title</a></li> 
}
</ul>

Да, — совсем не обязательно проверять дату изменения, можно проверять и дату создания, но это не принципиально.

И в заключении — большое спасибо Константину Томашевичу, за ценные советы по работе с методами класса xnode и написанию части кода примера.

2003-01-21 16:55:15 UTC parser snippet web xml