Что нового

Попытка создания структуры xml

valdur2000

Знающий
Сообщения
155
Репутация
7
Здравствуйте уважаемые Форумчане.
Код:
For $i = 1 To $a_ReturnArrayDaten[0][0]
    For $j = 1 To $a_ReturnArrayDaten[0][1]
Send ("<Registrierung>" & @LF)
Send ("<AuftragsId>" & $a_ReturnArrayDaten[$i][$j] & "</AuftragsId>" & @LF)
Send ("<VOId>" & $a_ReturnArrayDaten[$i][$j+1] & "</VOId>" & @LF)
Send ("<Privatkunde>" & @LF)
Send ("<Anrede>" & $a_ReturnArrayDaten[$i][$j+2] & "</Anrede>" & @LF)
Send ("<Vorname>" & $a_ReturnArrayDaten[$i][$j+3] & "</Vorname>" & @LF)
Send ("<Name>" & $a_ReturnArrayDaten[$i][$j+4] & "</Name>" & @LF)
Send ("</Privatkunde>" & @LF)
Send ("</Registrierung>" & @LF)
MsgBox(0,"","окончание строки")
Next
Next

Уважаемые подскажите пожалуйста почему i строка и j ряд не прирастают? Я вижу, что все Send'ы на весь цикл получают одинаковую [$i][$j] координату данных из массива, но как бороться с этим не понимаю.Попробовал увеличивать j прибавлением реально цифр (смотри пример вверху), но на второгм кругу начинается борода... А i не растет вообще. Визуально массив с $a_ReturnArrayDaten возвращается правильный.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
valdur2000
Структуру массива приведите, пожалуйста.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Код:
Dim $a_ReturnArrayDaten[2][5] = [[1,3,5,7,9], [2,4,6,8,0]]
For $i = 0 To UBound($a_ReturnArrayDaten) -1
	ConsoleWrite ("<Registrierung>" & @LF)
	ConsoleWrite (@TAB & "<AuftragsId>" & $a_ReturnArrayDaten[$i][0] & "</AuftragsId>" & @LF)
	ConsoleWrite (@TAB & "<VOId>" & $a_ReturnArrayDaten[$i][1] & "</VOId>" & @LF)
	ConsoleWrite (@TAB & "<Privatkunde>" & @LF)
	ConsoleWrite (@TAB & @TAB & "<Anrede>" & $a_ReturnArrayDaten[$i][2] & "</Anrede>" & @LF)
	ConsoleWrite (@TAB & @TAB & "<Vorname>" & $a_ReturnArrayDaten[$i][3] & "</Vorname>" & @LF)
	ConsoleWrite (@TAB & @TAB & "<Name>" & $a_ReturnArrayDaten[$i][4] & "</Name>" & @LF)
	ConsoleWrite (@TAB & "</Privatkunde>" & @LF)
	ConsoleWrite ("</Registrierung>" & @LF)
	MsgBox(0,"","окончание строки")
Next
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
Garrett
Как я понимаю, вы использовали эту функцию, что б сразу тестировать в консоли. Супер скорость. А вот если писать данные Send'ом скажем в открытый txt, то 50 строк пишет около 5 секунд. А если надо будет 20000 строк заполнить? А можно ли со скоростью ConsoleWrite писать данные? может в закрытый файл быстрее пишет, а может какой-нибудь другой текстовый редактор быстрее работает на прием? Всем, кто сталкивается с большими объемами данных, будет интересно.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
valdur2000
IMHO оптимальный вариант писать сразу или порциями в файл.
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
Garrett

IMHO оптимальный вариант писать сразу или порциями в файл.
Как я понимаю в закрытый, а что значит сразу или порциями? Но все равно Send'ом?

За код верхний спасибо. Я его чуть поменял и весь массив в txt записал. потом в XmlPad вставил и получился прекрасный Xml.
 

dwerf

Использует ArchLinux
Сообщения
478
Репутация
219
valdur2000 [?]
Как я понимаю в закрытый, а что значит сразу или порциями?
В открытый, только открываться файл может и самим AutoIt, причём без лишних окон.
Здесь справка по нужной функции. В конце есть пример.
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
dwerf
FileWriteLine то, что доктор прописал. Пишет построчно.
Скорость заполнения - поистине космическая. Спасибо.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
valdur2000 [?]
А если надо будет 20000 строк заполнить?

Код:
Dim $a_ReturnArrayDaten[3000][5]
Dim $sText = "1234567890", $sXML

For $x = 0 To UBound($a_ReturnArrayDaten) -1
	$a_ReturnArrayDaten[$x][0] = StringMid($sText, Random(1, StringLen($sText), 0), 10)
	$a_ReturnArrayDaten[$x][1] = StringMid($sText, Random(1, StringLen($sText), 0), 10)
	$a_ReturnArrayDaten[$x][2] = StringMid($sText, Random(1, StringLen($sText), 0), 10)
	$a_ReturnArrayDaten[$x][3] = StringMid($sText, Random(1, StringLen($sText), 0), 10)
	$a_ReturnArrayDaten[$x][4] = StringMid($sText, Random(1, StringLen($sText), 0), 10)
Next

$_T = TimerInit()

$hFile = FileOpen('test.xml', 1) ; Режим добавления записей в конец файла!!!

$sXML = "<?xml version=""1.0"" encoding=""UTF-8""?>" & @CRLF
$sXML &= "<root>" & @CRLF

For $i = 0 To UBound($a_ReturnArrayDaten) -1
	$sXML &= "<Registrierung id =""" & $i+1 & """>" & @CRLF
	$sXML &= @TAB & "<AuftragsId>" & $a_ReturnArrayDaten[$i][0] & "</AuftragsId>" & @CRLF
	$sXML &= @TAB & "<VOId>" & $a_ReturnArrayDaten[$i][1] & "</VOId>" & @CRLF
	$sXML &= @TAB & "<Privatkunde>" & @CRLF
	$sXML &= @TAB & @TAB & "<Anrede>" & $a_ReturnArrayDaten[$i][2] & "</Anrede>" & @CRLF
	$sXML &= @TAB & @TAB & "<Vorname>" & $a_ReturnArrayDaten[$i][3] & "</Vorname>" & @CRLF
	$sXML &= @TAB & @TAB & "<Name>" & $a_ReturnArrayDaten[$i][4] & "</Name>" & @CRLF
	$sXML &= @TAB & "</Privatkunde>" & @CRLF
	$sXML &= "</Registrierung>" & @CRLF
	
	; Добавляем каждые сто секций <Registrierung> в файл
	If Mod($i, 100) = 0 Then
		FileWrite($hFile, $sXML)
		$sXML = ""
	EndIf
Next

; Добавляем "хвост", если секций <Registrierung>  нечётное количество
$sXML &= "</root>"
FileWrite($hFile, $sXML)
$sXML = ""
FileClose($hFile)
	
; Затраченное время	
ConsoleWrite( Round(TimerDiff($_T)/1000, 2) & " сек." & @CRLF )
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
Здравствуйте уважаемые.
С процессом быстрой записи в файл с одновременным построением структуры Xml все понятно и реализовано. Работает реально быстро. А вот процесс получения данных из Excel'a оказался реально тормознутый. Реализовано так:

Код:
$s_FilePath = 'D:\test.xls'          ;файл Excel с данными
$file = FileOpen("D:\test.txt", 1) ;файл txt куда пишутся данные
$f_Visible = 0 ; 0 - в скрытом режиме, 1 - в открытом
;$vSheetDaten = 1 ; номер листа
$i_StartRowDaten = 2 ;номер начальной строки
$i_StartColumnDaten = 1 ;номер начальной колонки (3 - С)
$i_RowCntDaten = 500 ; 0 - строки считаем до последней заполненной ячейки, если не 0, то см. ниже
$i_ColCntDaten = 24 ;кол-во колонок, если 0, то см. выше
$o_Excel = _ExcelBookOpen ($s_FilePath, $f_Visible) ;xls открылся
$a_ReturnArrayDaten = _ExcelReadSheetToArray($o_Excel, $i_StartRowDaten, $i_StartColumnDaten, $i_RowCntDaten, $i_ColCntDaten)  ; тут создается массив, из которого потом берутся данные

For $i = 1 To UBound($a_ReturnArrayDaten) -1
    FileWriteLine($file, "<Registrierung>")
    FileWriteLine($file, @TAB & "<AuftragsId>" & $a_ReturnArrayDaten[$i][1] & "</AuftragsId>")
    FileWriteLine($file, @TAB & "<Id>" & $a_ReturnArrayDaten[$i][2] & "</Id>")

и так далее... с занесением строк в txt вопросов нету


массив с 500 строк реально ни разу не получилось сделать. прога заканчивала работу, так и не показав массив. 100 строк реально показать через 20 секунд. Но это значит 5 раз делать массивы по 100 строк... а можно забирать обрабатывать и писать из файла в файл не создавая массива? к чему он? прошу разъяснения и направления мысли.
Хотел добавить, что в ячейках Excel данные от 1 до 30 числобуквенных символов.
Может код Garrett отправленный: Сегодня в 10:52:25 отвечает на данный вопрос, тогда прошу дать знать, что б я проанализировал его с этой стороны..
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
valdur2000,
Может так попробовать:
Код:
#include <Excel.au3>

$sFileExcel = @ScriptDir & '\Test.xls'

$iStartTime = TimerInit()
;открываем файл Test.xls в скрытом режиме
$o_Excel = _ExcelBookOpen($sFileExcel, 0)
If @error Then
	MsgBox(16, 'Error', '_ExcelBookOpen')
	Exit
EndIf
;получаем массив со списком листов
$a_Sheet = _ExcelSheetList($o_Excel)
If @error Then
	MsgBox(16, 'Error', '_ExcelSheetList')
	_ExcelBookClose($o_Excel)
	If ProcessExists('EXCEL.EXE') Then ProcessClose('EXCEL.EXE')
	Exit
EndIf
;в цикле от первого листа до последнего
For $i = 1 To $a_Sheet[0]
	;активируем лист
	_ExcelSheetActivate($o_Excel, $i)
	If @error Then
		MsgBox(16, 'Error', '_ExcelSheetActivate')
		_ExcelBookClose($o_Excel)
		If ProcessExists('EXCEL.EXE') Then ProcessClose('EXCEL.EXE')
		Exit
	EndIf
	;сохраняем его как текстовый документ (разделитель - @TAB)
	_ExcelBookSaveAs($o_Excel, @ScriptDir & '\' & $a_Sheet[$i], 'txt')
	If @error Then
		MsgBox(16, 'Error', '_ExcelBookSaveAs')
		_ExcelBookClose($o_Excel)
		If ProcessExists('EXCEL.EXE') Then ProcessClose('EXCEL.EXE')
		Exit
	EndIf
Next
;закрываем Test.xls
_ExcelBookClose($o_Excel)
;у меня остается висеть в процессах, поэтому я закрываю процесс (у Вас, может быть следующая строка не нужна.)
If ProcessExists('EXCEL.EXE') Then ProcessClose('EXCEL.EXE')
;получили текстовые файлы. Имя - имя листа, кол-во - кол-во листов в Test.xls
;в цикле обрабатываем полученыые файлы
For $j = 1 To $a_Sheet[0]
	;задаем нужные нам значения
	$sString = '<?xml version="1.0" encoding="UTF-8"?>' & @CRLF & '<root>' & @CRLF
	$iCount = 0
	$i_RowCnt = 0 ;обрабатываем все строки до конца (если не 0, то можно задать кол-во строк для обработки
	$i_StartRow = 2;обработку начинаем со 2-ой строки
	;открываем, читаем, закрываем, удаляем очередной текстовый файл
	$hFile = FileOpen(@ScriptDir & '\' & $a_Sheet[$j] & '.txt')
	If $hFile = -1 Then ContinueLoop
	$sText = FileRead($hFile)
	FileClose($hFile)
	FileDelete(@ScriptDir & '\' & $a_Sheet[$j] & '.txt')
	;получаем массив строк
	$aText = StringSplit(StringStripCR($sText), @LF)
	If $aText[0] < 2 Then ContinueLoop
	;проверяем значения переменных, если они не правильные, исправляем.
	If Not $i_StartRow Or $i_StartRow >= $aText[0] Then $i_StartRow = 1
	If Not $i_RowCnt Then
		$i_RowCnt = $aText[0]
	Else
		$i_RowCnt += $i_StartRow - 1
	EndIf
	If $i_RowCnt > $aText[0] Then $i_RowCnt = $aText[0]
	;в цикле обрабатываем каждую строку
	For $i = $i_StartRow To $i_RowCnt
		$iCount += 1
		;получаем массив из строки по разделителю @TAB (аналог ячеек в Excel)
		$aTemp = StringSplit($aText[$i], @TAB)
		;если в Test.xls заполнены все пять первых колонок
		If $aTemp[0] = 5 Then
			;присваиваем строке $sString нужные значения:
			$sString &= '<Registrierung id ="' & $iCount & '">' & @CRLF & _
					@TAB & '<AuftragsId>' & $aTemp[1] & '</AuftragsId>' & @CRLF & _
					@TAB & '<VOId>' & $aTemp[2] & '</VOId>' & @CRLF & _
					@TAB & '<Privatkunde>' & @CRLF & _
					@TAB & @TAB & '<Anrede>' & $aTemp[3] & '</Anrede>' & @CRLF & _
					@TAB & @TAB & '<Vorname>' & $aTemp[4] & '</Vorname>' & @CRLF & _
					@TAB & @TAB & '<Name>' & $aTemp[5] & '</Name>' & @CRLF & _
					@TAB & '</Privatkunde>' & @CRLF & _
					'</Registrierung>' & @CRLF & @CRLF
		EndIf
	Next
	;открываем (создаем) файл xml с именем листа в кодировке UTF-8
	$hFile = FileOpen(@ScriptDir & '\' & $a_Sheet[$j] & '.xml', 128 + 2)
	If $hFile = -1 Then ContinueLoop
	;записываем в него созданную строку и закрываем
	FileWrite($hFile, $sString & '</root>')
	FileClose($hFile)
Next
;Все :)
MsgBox(64, 'Info', StringFormat('%.2f sec', TimerDiff($iStartTime) / 1000))

У меня на стареньком и слабом ноутбуке прикрепленный файл обрабатывается ~ за 3,5 секунды. (Excel 2003).

PS
В файле Test.xls в каждом листе должны быть заполнены первые 5 колонок. Надо еще делать проверки на ошибки, их в коде нет. Добавил.
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
madmasles
Извините, а вы не могли бы прокомментировать код, для понимания? Вы мне пару дней назад отвечали тоже по Excel'ю и так классно там откомментировались..
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
valdur2000,
Добавил комментарии.
Можно сохранять не в txt, а в csv, только если нет русского текста, тогда разделитель в строке будет ';' .
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
У меня на стареньком и слабом ноутбуке прикрепленный файл обрабатывается ~ за 3,5 секунды. (Excel 2003).
10000 строк по 10 столбцов с ни разу не повторяющимися данными, за 4,4 секунды! у меня потом xml раз в 5 дольше открывался. Дас ист фантастиш.
А можно дробилку выходящего xml'a сделать? например на каждые 100 или 500 заполненных ID строк данных?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
valdur2000 [?]
А можно дробилку выходящего xml'a сделать?
Если я Вас правильно понял, так?
Код:
#include <Excel.au3>

;задаем функцию, которая будет выполняться перед выходом
OnAutoItExitRegister('_CloseExcel_Hide')

$sDir = @ScriptDir
$sExcel = 'Test.xls'
$sFileExcel = $sDir & '\' & $sExcel
$iMaxString = 500 ;кол-во блоков в файле xml
$iStartTime = TimerInit()
;открываем файл Test.xls в скрытом режиме
$o_Excel = _ExcelBookOpen($sFileExcel, 0)
If @error Then
	MsgBox(16, 'Error', '_ExcelBookOpen')
	Exit
EndIf
;получаем массив со списком листов
$a_Sheet = _ExcelSheetList($o_Excel)
If @error Then
	MsgBox(16, 'Error', '_ExcelSheetList')
	_ExcelBookClose($o_Excel)
	Exit
EndIf
;в цикле от первого листа до последнего
For $i = 1 To $a_Sheet[0]
	;активируем лист
	_ExcelSheetActivate($o_Excel, $i)
	If @error Then
		MsgBox(16, 'Error', '_ExcelSheetActivate')
		_ExcelBookClose($o_Excel)
		Exit
	EndIf
	;сохраняем его как текстовый документ (разделитель - @TAB)
	_ExcelBookSaveAs($o_Excel, @ScriptDir & '\' & $a_Sheet[$i], 'txt')
	If @error Then
		MsgBox(16, 'Error', '_ExcelBookSaveAs')
		_ExcelBookClose($o_Excel)
		Exit
	EndIf
Next
;закрываем Test.xls
_ExcelBookClose($o_Excel)
;получили текстовые файлы. Имя - имя листа, кол-во - кол-во листов в Test.xls
;в цикле обрабатываем полученыые файлы
For $j = 1 To $a_Sheet[0]
	;задаем нужные нам значения
	$iCountXML = 0
	$sString = '<?xml version="1.0" encoding="UTF-8"?>' & @CRLF & '<root>' & @CRLF
	$iCount = 0
	$i_RowCnt = 0 ;обрабатываем все строки до конца (если не 0, то можно задать кол-во строк для обработки
	$i_StartRow = 2;обработку начинаем со 2-ой строки
	;открываем, читаем, закрываем, удаляем очередной текстовый файл
	$hFile = FileOpen(@ScriptDir & '\' & $a_Sheet[$j] & '.txt')
	If $hFile = -1 Then ContinueLoop
	$sText = FileRead($hFile)
	FileClose($hFile)
	FileDelete(@ScriptDir & '\' & $a_Sheet[$j] & '.txt')
	;получаем массив строк
	$aText = StringSplit(StringStripCR($sText), @LF)
	If $aText[0] < 2 Then ContinueLoop
	;проверяем значения переменных, если они не правильные, исправляем.
	If Not $i_StartRow Or $i_StartRow >= $aText[0] Then $i_StartRow = 1
	If Not $i_RowCnt Then
		$i_RowCnt = $aText[0]
	Else
		$i_RowCnt += $i_StartRow - 1
	EndIf
	If $i_RowCnt > $aText[0] Then $i_RowCnt = $aText[0]
	;в цикле обрабатываем каждую строку
	For $i = $i_StartRow To $i_RowCnt
		$iCount += 1
		;получаем массив из строки по разделителю @TAB (аналог ячеек в Excel)
		$aTemp = StringSplit($aText[$i], @TAB)
		;если в Test.xls заполнены все пять первых колонок
		If $aTemp[0] = 5 Then
			;присваиваем строке $sString нужные значения:
			$sString &= '<Registrierung id ="' & $iCount & '">' & @CRLF & _
					@TAB & '<AuftragsId>' & $aTemp[1] & '</AuftragsId>' & @CRLF & _
					@TAB & '<VOId>' & $aTemp[2] & '</VOId>' & @CRLF & _
					@TAB & '<Privatkunde>' & @CRLF & _
					@TAB & @TAB & '<Anrede>' & $aTemp[3] & '</Anrede>' & @CRLF & _
					@TAB & @TAB & '<Vorname>' & $aTemp[4] & '</Vorname>' & @CRLF & _
					@TAB & @TAB & '<Name>' & $aTemp[5] & '</Name>' & @CRLF & _
					@TAB & '</Privatkunde>' & @CRLF & _
					'</Registrierung>' & @CRLF & @CRLF
		EndIf
		If $iCount = $iMaxString Then
			$iCountXML += 1
			;открываем (создаем) файл xml с именем листа в кодировке UTF-8
			$hFile = FileOpen(@ScriptDir & '\' & $sExcel & '_XML\' & $a_Sheet[$j] & '\' & $iCountXML & '_' & _
					$a_Sheet[$j] & '.xml', 128 + 2 + 8)
			If $hFile = -1 Then ContinueLoop
			;записываем в него созданную строку и закрываем
			FileWrite($hFile, $sString & '</root>')
			FileClose($hFile)
			$sString = '<?xml version="1.0" encoding="UTF-8"?>' & @CRLF & '<root>' & @CRLF
			$iCount = 0
		EndIf
	Next
	$iCountXML += 1
	;открываем (создаем) файл xml с именем листа в кодировке UTF-8
	$hFile = FileOpen(@ScriptDir & '\' & $sExcel & '_XML\' & $a_Sheet[$j] & '\' & $iCountXML & '_' & _
			$a_Sheet[$j] & '.xml', 128 + 2 + 8)
	If $hFile = -1 Then ContinueLoop
	;записываем в него созданную строку и закрываем
	FileWrite($hFile, $sString & '</root>')
	FileClose($hFile)
Next
;Все :)
MsgBox(64, 'Info', StringFormat('%.2f sec', TimerDiff($iStartTime) / 1000))

Func _CloseExcel_Hide()
	;закрывает скрытые окна Excel, чтобы не висел EXCEL.EXE в процессах
	Local $a_List
	$a_List = WinList('[Class:XLMAIN]')
	If $a_List[0][0] Then
		For $i = 1 To $a_List[0][0]
			If Not BitAND(WinGetState($a_List[$i][1]), 2) Then
				WinClose($a_List[$i][1])
			EndIf
		Next
	EndIf
EndFunc   ;==>_CloseExcel_Hide
 
Автор
V

valdur2000

Знающий
Сообщения
155
Репутация
7
Спасибо большое. все отлично работает. в моем случае пришлось поменять в
Код:
FileOpen
128 на 256, а то приходилось каждый раз в XMLPad'e пересохранять. я не очень понял что такое BOM в кодировке UTF-8, который не надо перезаписывать, но почитав справку и поменяв 128 на 256 все заработало. Спасибо. Тема закрыта.
 
Верх