Что нового

[Элементы GUI] TreeView из большого XML файла

IgRo

Знающий
Сообщения
65
Репутация
5
Имеется XML-файл (150мб) со структурой вида:
Код:
<root>
  <elem>
    <Ref>001</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 1</Description>
    <Parent>000</Parent>
  </elem>
  <elem>
    <Ref>002</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 11</Description>
    <Parent>001</Parent>
  </elem>
  <elem>
    <Ref>003</Ref>
    <IsFolder>False</IsFolder>
    <Description>Item    11</Description>
    <Parent>001</Parent>
  </elem>
  <elem>
    <Ref>004</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 2</Description>
    <Parent>000</Parent>
  </elem>
</root>
где Ref – уникальный идентификатор
IsFolder – признак группы
Description – наименование
Parent - ссылка на Ref родителя
Кол-во узлов <elem> более 30 тыс. из них с IsFolder=True менее 100, глубина вложении около 3
Помогите получить TreeView с максимальной скоростью вида
Folder 1
Folder 11
Item 11
Folder 2
 

XpycT

Скриптер
Сообщения
380
Репутация
133
IgRo
Код:
#include <GUIConstantsEx.au3>

Global $sXML = @ScriptDir & "\000.xml"

Global $oXML = ObjCreate("Msxml2.DOMDocument.6.0")

$oXML.Load($sXML)

$oElements = $oXML.SelectNodes("root/elem")
If $oXML.ParseError.ErrorCode <> 0 Then Exit 99 * 0 + ConsoleWrite("$oXML.SelectNodes | Error > " & $oXML.ParseError.Reason & @CR)

Global $aTVElem[$oElements.Length + 1]

$Form1 = GUICreate("Form1", 400, 600, -1, -1)
$aTVElem[0] = GUICtrlCreateTreeView(5, 5, 390, 590)

GUISetState(@SW_SHOW)

_LoadElementsFromXML($oElements)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

Func _LoadElementsFromXML($oNodes)
	For $oNode In $oNodes
		$iRef = $oNode.SelectSingleNode("Ref").Text
		$fIsFolder = ($oNode.SelectSingleNode("IsFolder").Text = True)
		$sDescription = $oNode.SelectSingleNode("Description").Text
		$iParent = $oNode.SelectSingleNode("Parent").Text

		$aTVElem[$iRef] = GUICtrlCreateTreeViewItem($sDescription, $aTVElem[$iParent])
	Next
EndFunc
 
Автор
I

IgRo

Знающий
Сообщения
65
Репутация
5
Уточню
Ref - имеет формат GUID (Globally Unique Identifier) — статистически уникальный 128-битный идентификатор
Структура идентификатора:
GUID STRUCT
Data1 dd ‘4 байта
Data2 dw ‘2 байта
Data3 dw ‘2 байта
Data4 db 8 ‘8 байт
GUID ENDS
Например, '22345200-abe8-4f60-90c8-0d43c5f6c0f6'[1] соответствует шестнадцатеричному 128-битному числу 0x00523422E8AB604F90C80D43C5F6C0F6 :stars:


Код:
<root>
  <elem>
    <Ref>1d377bce-d8c1-11de-8008-0015170f31a8</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 1</Description>
    <Parent>00000000-0000-0000-0000-000000000000</Parent>
  </elem>
  <elem>
    <Ref>1d377bd0-d8c1-11de-8008-0015170f31a8</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 11</Description>
    <Parent>1d377bce-d8c1-11de-8008-0015170f31a8</Parent>
  </elem>
  <elem>
    <Ref>1d377bd4-d8c1-11de-8008-0015170f31a8</Ref>
    <IsFolder>False</IsFolder>
    <Description>Item    11</Description>
    <Parent>1d377bce-d8c1-11de-8008-0015170f31a8</Parent>
  </elem>
  <elem>
    <Ref>1d377bda-d8c1-11de-8008-0015170f31a8</Ref>
    <IsFolder>True</IsFolder>
    <Description>Folder 2</Description>
     <Parent>00000000-0000-0000-0000-000000000000</Parent>
  </elem>
</root>
 
Автор
I

IgRo

Знающий
Сообщения
65
Репутация
5
Генератор XML файла
Код:
$FileNameXML = 'Tree.XML'
$FileXML = FileOpen($FileNameXML, 2)
FileWrite($FileXML, "<Root>" & @CRLF)
For $X1 = 1 To 10
	$Ref1 = _WinAPI_CreateGUID()
	FileWrite($FileXML, "<Elem>" & @CRLF)
	FileWrite($FileXML, "<Ref>" & $Ref1 & "</Ref>" & @CRLF)
	FileWrite($FileXML, "<IsFolder>True</IsFolder>" & @CRLF)
	FileWrite($FileXML, "<Description>Folder 0_" & $X1 & "</Description>" & @CRLF)
	FileWrite($FileXML, "<Parent>00000000-0000-0000-0000-000000000000</Parent>" & @CRLF)
	FileWrite($FileXML, "</Elem>" & @CRLF)
	For $X2 = 1 To 30
		$Ref2 = _WinAPI_CreateGUID()
		FileWrite($FileXML, "<Elem>" & @CRLF)
		FileWrite($FileXML, "<Ref>" & $Ref2 & "</Ref>" & @CRLF)
		FileWrite($FileXML, "<IsFolder>True</IsFolder>" & @CRLF)
		FileWrite($FileXML, "<Description>Folder " & $X1 & "_" & $X1 & "</Description>" & @CRLF)
		FileWrite($FileXML, "<Parent>" & $Ref1 & "</Parent>" & @CRLF)
		FileWrite($FileXML, "</Elem>" & @CRLF)
		For $X3 = 1 To 100;0
			$Ref3 = _WinAPI_CreateGUID()
			FileWrite($FileXML, "<Elem>" & @CRLF)
			FileWrite($FileXML, "<Ref>" & $Ref3 & "</Ref>" & @CRLF)
			FileWrite($FileXML, "<IsFolder>False</IsFolder>" & @CRLF)
			FileWrite($FileXML, "<Description>Elem " & $X2 & "_" & $X3 & "</Description>" & @CRLF)
			FileWrite($FileXML, "<Parent>" & $Ref2 & "</Parent>" & @CRLF)
			FileWrite($FileXML, "</Elem>" & @CRLF)
		Next
	Next
Next
FileWrite($FileXML, "</Root>" & @CRLF)
FileClose($FileXML)

Func _WinAPI_CreateGUID()
	Local Const $tagGUID = "int Data1;short Data2;short Data3;byte Data4[8]"
	Local $tData = DllStructCreate('wchar[39]')
	Local $tGUID = DllStructCreate($tagGUID)
	Local $Return
	$Return = DllCall('ole32.dll', 'uint', 'CoCreateGuid', 'ptr', DllStructGetPtr($tGUID))
	If @error Then Return SetError(1, 1, 0)
	If $Return[0] Then Return SetError(1, $Return[0], 0)

	$Return = DllCall('ole32.dll', 'int', 'StringFromGUID2', 'ptr', DllStructGetPtr($tGUID), 'ptr', DllStructGetPtr($tData), 'int', 39)
	If(@error) Or(Not $Return[0]) Then Return SetError(1, 1, 0)
	;Return DllStructGetData($tData, 1)
	Return StringMid ( DllStructGetData($tData, 1), 2, 36 )
EndFunc   ;==>_WinAPI_CreateGUID




Добавлено:
Сообщение автоматически объединено:

выход наверное в теме
http://autoit-script.ru/index.php/topic,11744.0.html
 

XpycT

Скриптер
Сообщения
380
Репутация
133
IgRo
Код:
#include <GUIConstantsEx.au3>

Global $sXML = StringTrimRight(@ScriptFullPath, 4) & ".xml"

_GenerateXMLFile()

Global $oXML = ObjCreate("Msxml2.DOMDocument.6.0")

$oXML.Load($sXML)

$oElements = $oXML.SelectNodes("Root/Elem")
If $oXML.ParseError.ErrorCode <> 0 Then Exit 99 * 0 + ConsoleWrite("$oXML.SelectNodes | Error > " & $oXML.ParseError.Reason & @CR)

Global $aTVElem[$oElements.Length + 2][2] = [[$oElements.Length, 2], ["00000000-0000-0000-0000-000000000000", ""]]

$Form1 = GUICreate("Form1", 400, 600, -1, -1)
$aTVElem[1][1] = GUICtrlCreateTreeView(5, 5, 390, 590)

GUISetState(@SW_SHOW)

_LoadElementsFromXML($oElements)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

Func _LoadElementsFromXML($oNodes)
	For $oNode In $oNodes
		Dim $iParentIn = -1, $iElemIn = $aTVElem[0][1]

		$sRef = $oNode.SelectSingleNode("Ref").Text
		$fIsFolder = ($oNode.SelectSingleNode("IsFolder").Text = True)
		$sDescription = $oNode.SelectSingleNode("Description").Text
		$sParent = $oNode.SelectSingleNode("Parent").Text

		For $r = 1 To UBound($aTVElem) - 1
			If $aTVElem[$r][0] = $sParent Then ExitLoop Assign("iParentIn", $r, 0 + 1)
		Next

		$aTVElem[$iElemIn][0] = $sRef
		$aTVElem[$iElemIn][1] = GUICtrlCreateTreeViewItem($sDescription, $aTVElem[$iParentIn][1])

		$aTVElem[0][1] += 1
	Next
EndFunc

Func _GenerateXMLFile()
	If FileExists($sXML) Then FileDelete($sXML)

	$hF = FileOpen($sXML, 2)

	FileWrite($hF, "<Root>" & @CRLF)

	For $X1 = 1 To 5
		$Ref1 = _WinAPI_CreateGUID()

		FileWrite($hF, "<Elem>" & @CRLF)
		FileWrite($hF, "<Ref>" & $Ref1 & "</Ref>" & @CRLF)
		FileWrite($hF, "<IsFolder>True</IsFolder>" & @CRLF)
		FileWrite($hF, "<Description>Folder 0_" & $X1 & "</Description>" & @CRLF)
		FileWrite($hF, "<Parent>00000000-0000-0000-0000-000000000000</Parent>" & @CRLF)
		FileWrite($hF, "</Elem>" & @CRLF)

		For $X2 = 1 To 5
			$Ref2 = _WinAPI_CreateGUID()

			FileWrite($hF, "<Elem>" & @CRLF)
			FileWrite($hF, "<Ref>" & $Ref2 & "</Ref>" & @CRLF)
			FileWrite($hF, "<IsFolder>True</IsFolder>" & @CRLF)
			FileWrite($hF, "<Description>Folder " & $X1 & "_" & $X1 & "</Description>" & @CRLF)
			FileWrite($hF, "<Parent>" & $Ref1 & "</Parent>" & @CRLF)
			FileWrite($hF, "</Elem>" & @CRLF)

			For $X3 = 1 To 5
				$Ref3 = _WinAPI_CreateGUID()

				FileWrite($hF, "<Elem>" & @CRLF)
				FileWrite($hF, "<Ref>" & $Ref3 & "</Ref>" & @CRLF)
				FileWrite($hF, "<IsFolder>False</IsFolder>" & @CRLF)
				FileWrite($hF, "<Description>Elem " & $X2 & "_" & $X3 & "</Description>" & @CRLF)
				FileWrite($hF, "<Parent>" & $Ref2 & "</Parent>" & @CRLF)
				FileWrite($hF, "</Elem>" & @CRLF)
			Next
		Next
	Next

	FileWrite($hF, "</Root>" & @CRLF)

	FileClose($hF)
EndFunc

Func _WinAPI_CreateGUID()
	Local Const $tagGUID = "int Data1;short Data2;short Data3;byte Data4[8]"
	Local $tData = DllStructCreate('wchar[39]')
	Local $tGUID = DllStructCreate($tagGUID)
	Local $Return

	$Return = DllCall('ole32.dll', 'uint', 'CoCreateGuid', 'ptr', DllStructGetPtr($tGUID))
	If @error Then Return SetError(1, 1, 0)
	If $Return[0] Then Return SetError(1, $Return[0], 0)

	$Return = DllCall('ole32.dll', 'int', 'StringFromGUID2', 'ptr', DllStructGetPtr($tGUID), 'ptr', DllStructGetPtr($tData), 'int', 39)
	If(@error) Or(Not $Return[0]) Then Return SetError(1, 1, 0)

	; Return DllStructGetData($tData, 1)
	Return StringMid(DllStructGetData($tData, 1), 2, 36)
EndFunc   ;==>_WinAPI_CreateGUID



Добавлено:
Сообщение автоматически объединено:

Вот еще один вариант только уже с использованием Полезняшки от CreatoR'а Аналог ассоциативного массива

Код:
#include <GUIConstantsEx.au3>

Global $sXML = StringTrimRight(@ScriptFullPath, 4) & ".xml"

Global $oXML = ObjCreate("Msxml2.DOMDocument.6.0"), $oTVElem = ObjCreate("Scripting.Dictionary")

_GenerateXMLFile()

$oXML.Load($sXML)

$oElements = $oXML.SelectNodes("Root/Elem")
If $oXML.ParseError.ErrorCode <> 0 Then Exit 99 * 0 + ConsoleWrite("$oXML.SelectNodes | Error > " & $oXML.ParseError.Reason & @CR)

$Form1 = GUICreate("Form1", 400, 600, -1, -1)
$iTVCtrl = GUICtrlCreateTreeView(5, 5, 390, 590)

$oTVElem.Add("00000000-0000-0000-0000-000000000000", $iTVCtrl)

GUISetState(@SW_SHOW)

_LoadElementsFromXML($oElements)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

Func _LoadElementsFromXML($oNodes)
	For $oNode In $oNodes
		$sRef = $oNode.SelectSingleNode("Ref").Text
		$fIsFolder = ($oNode.SelectSingleNode("IsFolder").Text = True)
		$sDescription = $oNode.SelectSingleNode("Description").Text
		$sParent = $oNode.SelectSingleNode("Parent").Text

		$iTCItem = GUICtrlCreateTreeViewItem($sDescription, $oTVElem.Item($sParent))

		$oTVElem.Add($sRef, $iTCItem)
	Next
EndFunc

Func _GenerateXMLFile()
	If FileExists($sXML) Then FileDelete($sXML)

	$hF = FileOpen($sXML, 2)

	FileWrite($hF, "<Root>" & @CRLF)

	For $X1 = 1 To 5
		$Ref1 = _WinAPI_CreateGUID()

		FileWrite($hF, "<Elem>" & @CRLF)
		FileWrite($hF, "<Ref>" & $Ref1 & "</Ref>" & @CRLF)
		FileWrite($hF, "<IsFolder>True</IsFolder>" & @CRLF)
		FileWrite($hF, "<Description>Folder 0_" & $X1 & "</Description>" & @CRLF)
		FileWrite($hF, "<Parent>00000000-0000-0000-0000-000000000000</Parent>" & @CRLF)
		FileWrite($hF, "</Elem>" & @CRLF)

		For $X2 = 1 To 5
			$Ref2 = _WinAPI_CreateGUID()

			FileWrite($hF, "<Elem>" & @CRLF)
			FileWrite($hF, "<Ref>" & $Ref2 & "</Ref>" & @CRLF)
			FileWrite($hF, "<IsFolder>True</IsFolder>" & @CRLF)
			FileWrite($hF, "<Description>Folder " & $X1 & "_" & $X1 & "</Description>" & @CRLF)
			FileWrite($hF, "<Parent>" & $Ref1 & "</Parent>" & @CRLF)
			FileWrite($hF, "</Elem>" & @CRLF)

			For $X3 = 1 To 5
				$Ref3 = _WinAPI_CreateGUID()

				FileWrite($hF, "<Elem>" & @CRLF)
				FileWrite($hF, "<Ref>" & $Ref3 & "</Ref>" & @CRLF)
				FileWrite($hF, "<IsFolder>False</IsFolder>" & @CRLF)
				FileWrite($hF, "<Description>Elem " & $X2 & "_" & $X3 & "</Description>" & @CRLF)
				FileWrite($hF, "<Parent>" & $Ref2 & "</Parent>" & @CRLF)
				FileWrite($hF, "</Elem>" & @CRLF)
			Next
		Next
	Next

	FileWrite($hF, "</Root>" & @CRLF)

	FileClose($hF)
EndFunc

Func _WinAPI_CreateGUID()
	Local Const $tagGUID = "int Data1;short Data2;short Data3;byte Data4[8]"
	Local $tData = DllStructCreate('wchar[39]')
	Local $tGUID = DllStructCreate($tagGUID)
	Local $Return

	$Return = DllCall('ole32.dll', 'uint', 'CoCreateGuid', 'ptr', DllStructGetPtr($tGUID))
	If @error Then Return SetError(1, 1, 0)
	If $Return[0] Then Return SetError(1, $Return[0], 0)

	$Return = DllCall('ole32.dll', 'int', 'StringFromGUID2', 'ptr', DllStructGetPtr($tGUID), 'ptr', DllStructGetPtr($tData), 'int', 39)
	If(@error) Or(Not $Return[0]) Then Return SetError(1, 1, 0)

	; Return DllStructGetData($tData, 1)
	Return StringMid(DllStructGetData($tData, 1), 2, 36)
EndFunc   ;==>_WinAPI_CreateGUID
 
Автор
I

IgRo

Знающий
Сообщения
65
Репутация
5
По тестам тормозит функция SelectSingleNode()
Буду использовать импорт XML в SQLite
http://autoit-script.ru/index.php/topic,13244.msg84718.html#new
XpycT
с использованием ассоциативного массива
не работает но подход очень интересный


Добавлено:
Сообщение автоматически объединено:

Я пришёл к таким выводам:
1 XML избыточный формат данных поэтому имеет большой размер и обработка его занимает много времени.
2 Конвертируем XML в таблицы SQLite
3 Для этого с помощью утилиты от MS “xsd.exe” строим XSD схему
4 На основе XSD схемы строим запросы на создание таблиц в SQLite.
5 По XML строим запросы на заполнение таблиц
6 Создаем SQL запросам для постройки дерева.
 
Верх