Перейти к содержимому


- - - - -

Конвертирование XML to XLS


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 7

#1 XmaN

XmaN

    Активный участник

  • Модераторы
  • PipPipPipPipPipPipPip
  • 8 277 сообщений
  • Пол: мужской
  • Город: Псков

Отправлено 09.08.2010 - 11:21

Надоело вручную обновлять xls прайс, хочу автоматизировать. У меня уже настроена автоматическая выгрузка каталога в xml, хочу из неё делать xls. Выглядит вот так (оставил 2 товара и 2 группы, в xls из этого куска должно выводить 4 строчки):
Скрытый текст
На сервере имеется FreeBSD. Как я понял действовать нужно через Perl и модуль Spreadsheet::WriteExcel::FromXML. Сделал скрипт как на страничке модуля:
#!/usr/local/bin/perl
	  use strict;
	  use warnings;
	  use Spreadsheet::WriteExcel::FromXML;
	   my $fromxml = Spreadsheet::WriteExcel::FromXML->new("price.xml");
	   $fromxml->parse;
	   $fromxml->buildSpreadsheet;
	   $fromxml->writeFile("price.xls");

Запускаю, сыпятся ошибки вроде этой (консоль не юникодовая, поэтому русские сивмолы не выводятся нормально):

Цитата

at /usr/local/lib/perl5/site_perl/5.8.9/Spreadsheet/WriteExcel/FromXML.pm line 325
        Spreadsheet::WriteExcel::FromXML::_processTree('Spreadsheet::WriteExcel::FromXML=HASH(0x800f0d210)', 'ARRAY(0x8017fa6c0)', 'піп╣пҐп╟1', 'SCALAR(0x801f3f250)', 'SCALAR(0x801f3f270)', undef, undef) called at /usr/local/lib/perl5/site_perl/5.8.9/Spreadsheet/WriteExcel/FromXML.pm line 328
        Spreadsheet::WriteExcel::FromXML::_processTree('Spreadsheet::WriteExcel::FromXML=HASH(0x800f0d210)', 'ARRAY(0x8017fa3a0)', 'п╒п╬п╡п╟я─', 'SCALAR(0x801f3f250)', 'SCALAR(0x801f3f270)', undef, undef) called at /usr/local/lib/perl5/site_perl/5.8.9/Spreadsheet/WriteExcel/FromXML.pm line 328
        Spreadsheet::WriteExcel::FromXML::_processTree('Spreadsheet::WriteExcel::FromXML=HASH(0x800f0d210)', 'ARRAY(0x8017f97c0)', 'п п╬п╪п©я▄я▌я┌п╣я─п÷п╩п╟пЇп╟', 'SCALAR(0x801f3f250)', 'SCALAR(0x801f3f270)') called at /usr/local/lib/perl5/site_perl/5.8.9/Spreadsheet/WriteExcel/FromXML.pm line 186
        Spreadsheet::WriteExcel::FromXML::parse('Spreadsheet::WriteExcel::FromXML=HASH(0x800f0d210)') called at ./xmltest line 6
Unrecognized type 'піп╣пҐп╟2'.  Ignored.
Дальше ступор, на Perl никогда не писал.
Собсно мне нужно выгружать только <Код>, <Наименование>, <Цена1>, <Цена2> и некоторую функцию от <Количество> (т.е. например кол-во < 3шт - 1 палочка, от 3 до 7шт - 2 палочки, от 7шт - 3 палочки.) Чтоб получилось примерно как щас - http://plaza-pskov.r...files/price.xls

Или проще из MySQL выборку сделать?

Сообщение отредактировал XmaN: 09.08.2010 - 11:22


#2 muhas

muhas

    Слава роботам!

  • Модераторы
  • PipPipPipPipPipPipPipPipPipPip
  • 24 093 сообщений
  • Пол: мужской

Отправлено 09.08.2010 - 11:58

я в перле бестолочь, но посмотри сюда http://www.perlmonks...d=635459;part=1

хотя в портах фряшных имеется xls2xml http://www.freebsd.o...xtproc/xls2xml/
а вообще в перле есть xml2csv - а дальше уже и выводи csv по работе с ним думаю проблем не возникнет - для вебязыков модули имеются

#3 XmaN

XmaN

    Активный участник

  • Модераторы
  • PipPipPipPipPipPipPip
  • 8 277 сообщений
  • Пол: мужской
  • Город: Псков

Отправлено 09.08.2010 - 12:34

Просмотр сообщенияmuhas (09.08.2010 - 11:58) писал:

я в перле бестолочь, но посмотри сюда http://www.perlmonks...d=635459;part=1

хотя в портах фряшных имеется xls2xml http://www.freebsd.o...xtproc/xls2xml/
Это все XLS to XML, а мне надо наоборот.

Цитата

а вообще в перле есть xml2csv - а дальше уже и выводи csv по работе с ним думаю проблем не возникнет - для вебязыков модули имеются
Квест какой-то получается :) Вообще мне проще выборка из MySQL чем парсинг xml, наверно буду думать в эту сторону. Но с csv тоже идея кстати.

Сообщение отредактировал XmaN: 09.08.2010 - 12:37


#4 ancient

ancient

    Постоянный участник

  • Пользователи
  • PipPip
  • 211 сообщений
  • Пол: мужской

Отправлено 09.08.2010 - 12:46

Судя по исходникам модуля ошибка Unrecognized type из-за того, что тег может принимать только следующие значения:
worksheet, row, cell, format, range, margins. А у тебя они "Цена1" и т.п. Заголовки по идее где-то в атрибутах должны быть заданы - надо мануал читать.

Должно быть примерно так:
<?xml version="1.0" ?>
<!DOCTYPE workbook SYSTEM "../FromXML.dtd">

<workbook>
  <worksheet title="Заголовок прайса">
	<format name="heading" bold="1" bg_color="yellow" align="center" font="Courier" size="12" italic="1" />
	<row format="heading"> <!-- Заголовок таблицы -->
	  <cell>id</cell>
	  <cell>товар</cell>
	  <cell>цена</cell>
	</row>

	<row> <!-- Элементы -->
	  <cell type="number">1111</cell>
	  <cell>Имя товара</cell>
	  <cell>53534</cell>
	</row>
  </worksheet>
</workbook>


Сообщение отредактировал ancient: 09.08.2010 - 12:53


#5 XmaN

XmaN

    Активный участник

  • Модераторы
  • PipPipPipPipPipPipPip
  • 8 277 сообщений
  • Пол: мужской
  • Город: Псков

Отправлено 09.08.2010 - 12:57

Просмотр сообщенияancient (09.08.2010 - 12:46) писал:

Судя по исходникам модуля ошибка Unrecognized type из-за того, что тег может принимать только следующие значения:
worksheet, row, cell, format, range, margins. А у тебя они "Цена1" и т.п. Заголовки по идее где-то в адрибутах должны быть заданы - надо мануал читать.
Мануал коротенький, я не очень понял как оно должно работать. Про worksheet, row, cell, format, range, margins я тоже догадался, но не понял как подогнать под мои нужды. То ли через переменные в скрипте конвертирования, то ли сам модуль править.
Попробую XML подогнать как в твоем примере.

Сообщение отредактировал XmaN: 09.08.2010 - 12:59


#6 ancient

ancient

    Постоянный участник

  • Пользователи
  • PipPip
  • 211 сообщений
  • Пол: мужской

Отправлено 09.08.2010 - 12:59

Просмотр сообщенияXmaN (09.08.2010 - 12:57) писал:

Мануал коротенький, я не очень понял как оно должно работать. Про worksheet, row, cell, format, range, margins я тоже догадался, но не понял как подогнать под мои нужды. То ли через переменные в скрипте конвертирования, то ли сам модуль править.

По моему, проще (и правильнее) в конвертере все это сделать.

#7 muhas

muhas

    Слава роботам!

  • Модераторы
  • PipPipPipPipPipPipPipPipPipPip
  • 24 093 сообщений
  • Пол: мужской

Отправлено 09.08.2010 - 13:27

Просмотр сообщенияXmaN (09.08.2010 - 12:34) писал:

Это все XLS to XML, а мне надо наоборот..
неудачно я значит пост распарсил =)

вот начало решения на пыхе
function simpleXMLToArray($xml,
					$flattenValues=true,
					$flattenAttributes = true,
					$flattenChildren=true,
					$valueKey='@value',
					$attributesKey='@attributes',
					$childrenKey='@children'){

		$return = array();
		if(!($xml instanceof SimpleXMLElement)){return $return;}
		$name = $xml->getName();
		$_value = trim((string)$xml);
		if(strlen($_value)==0){$_value = null;};

		if($_value!==null){
			if(!$flattenValues){$return[$valueKey] = $_value;}
			else{$return = $_value;}
		}

		$children = array();
		$first = true;
		foreach($xml->children() as $elementName => $child){
			$value = simpleXMLToArray($child, $flattenValues, $flattenAttributes, $flattenChildren, $valueKey, $attributesKey, $childrenKey);
			if(isset($children[$elementName])){
				if($first){
					$temp = $children[$elementName];
					unset($children[$elementName]);
					$children[$elementName][] = $temp;
					$first=false;
				}
				$children[$elementName][] = $value;
			}
			else{
				$children[$elementName] = $value;
			}
		}
		if(count($children)>0){
			if(!$flattenChildren){$return[$childrenKey] = $children;}
			else{$return = array_merge($return,$children);}
		}

		$attributes = array();
		foreach($xml->attributes() as $name=>$value){
			$attributes[$name] = trim($value);
		}
		if(count($attributes)>0){
			if(!$flattenAttributes){$return[$attributesKey] = $attributes;}
			else{$return = array_merge($return, $attributes);}
		}
	   
		return $return;
	}

$file_name = './bla.xml'; // файло
//------------------------------------------------------------
$tmp_db =  file_get_contents($file_name);
$tmp_db = str_replace ( '&', ' ', $tmp_db);
$tmp_db = simplexml_load_string($tmp_db);

$tmp_db=simpleXMLToArray($tmp_db);
в итоге в $tmp_db массив из твоего xml, дальше foreach и тупо пиши в csv (а csv вроде как открывается екселем как екселевский файл, т.е. значит при file_put_contents  главное указать нужное расширение. так же exel может быть как таблица), хотя можно и заморочится и в exel уже генерить - но я не заморачивался, посему не знаю как

кстати в том файле что из первого поста взял фигня получается. масив с товаром смотри...
Array
(
	[Группа] => Array
		(
			[0] => Array
				(
					[Наименование] => Мониторы
					[Код] => 1
					[РодительскийКод] => 0
				)

			[1] => Array
				(
					[Наименование] => Монитор 17"
					[Код] => 7774
					[РодительскийКод] => 1
				)

		)

	[Товар] => Array
		(
			[Наименование] => Монитор 17" TFT LG L1742SE-SF silver 5ms
			[Характеристика] => 1280x1024, 300 кд/м2, 700:1, 5 мс, 160°/160°, VGA
			[Код] => 22985
			[РодительскийКод] => 7774
			[Цена1] => 5100
			[Цена2] => 5400
			[Цена3] => 5000
			[Цена4] => 4900
			[Количество] => 0
			[0] => Array
				(
					[Наименование] => Монитор 17" TFT Philips 17S1SB, black 5ms, DVI
					[Характеристика] => 1280x1024, 250 кд/м2, 800:1, 5 мс, DVI, VGA
					[Код] => 22719
					[РодительскийКод] => 7774
					[Цена1] => 5200
					[Цена2] => 5500
					[Цена3] => 5100
					[Цена4] => 5000
					[Количество] => 2
				)

		)

)


зы. удачного прохождения сего квеста

#8 XmaN

XmaN

    Активный участник

  • Модераторы
  • PipPipPipPipPipPipPip
  • 8 277 сообщений
  • Пол: мужской
  • Город: Псков

Отправлено 09.08.2010 - 20:53

Забил на неведомый мне Perl, нашёл модуль Spreadsheet_Excel_Writer для PHP. На сайте уже был скрипт парсинга xml и занесения в MySQL, мне оставалось переделать его под свои нужды.
ver 0.1 beta готова :) Мне осталось только отформатировать покрасивей xls таблицу и добавить функцию проставления палок вместо конкретного количества.

<?php
require_once('Spreadsheet/Excel/Writer.php');

	if (is_file('price.xml') && is_readable('price.xml'))
	{

		$import_xml = simplexml_load_file('price.xml');
		$import_array = extract_XML($import_xml);
		if (is_array($import_array))
		{
		 $workbook = new Spreadsheet_Excel_Writer();
		 $workbook->send('price.xls');
		 $workbook->setVersion(8);
		 $worksheet =& $workbook->addWorksheet('Price');
		 $worksheet->setInputEncoding('utf-8');
		 $worksheet->write(0, 0, 'Код');
		 $worksheet->write(0, 1, 'Наименование');
		 $worksheet->write(0, 2, 'Цена, руб');
		 $worksheet->write(0, 3, 'Цена безнал, кредит, руб');
		 $worksheet->write(0, 4, 'Наличие');
		 
			$col = 0;
		 	foreach ($import_array as $vals)
			{
				if (array_key_exists("Группа", $vals))
				{
					$col++;
					$worksheet->write($col, 0, $vals["Группа"]["Наименование"]);
				}
				if (array_key_exists("Товар", $vals))
				{
					$col++;
					$worksheet->write($col, 0, $vals["Товар"]["Код"]);
					$worksheet->write($col, 1, $vals["Товар"]["Наименование"]);
					$worksheet->write($col, 2, $vals["Товар"]["Цена1"]);
					$worksheet->write($col, 3, $vals["Товар"]["Цена2"]);
					$worksheet->write($col, 4, $vals["Товар"]["Количество"]);
				}
				
			}
			$workbook->close();
			
		
		}
	}
?>

Ещё у меня была заинклужена функция extract_XML. Я не вникал как она работает, главное что работает :)
function extract_XML($xml)
{
	if (!($xml->children()))
	{
		return (string) $xml;
	}
	foreach ($xml->children() as $child)
	{
		$name = $child->getName();
		if (count($xml->$name) == 1)
		{
			$element[$name] = extract_XML($child);
		}
		else
		{
			$element[][$name] = extract_XML($child);
		}
	}
	return $element;
}

ancient, muhas  спасибо что пытались помочь и натолкнули на некоторые мысли :)

Сообщение отредактировал XmaN: 09.08.2010 - 20:58





Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 скрытых пользователей