Access

 MS Access & XML & Baza miejscowości i ulic TERYT.

Krajowy Rejestr Urzędowy Podziału Terytorialnego Kraju (TERYT)

TERC (wykaz jednostek podziału terytorialnego)

• Stan na dzień 03 marca 2018 roku

Na stronie Przetwarzanie pliku WMRODZ.xml z rejestru TERYT zapoznaliśmy się ze strukturą pliku i metodą zapisu danych z tego pliku do tabeli bazy danych MS Access. Teraz przyszła kolej na następny plik z rejestru TERYT. Jest nim plik TERC.xml zawierający identyfikatory i nazwy jednostek podziału terytorialnego. Plik ten, jak i pozostałe, możemy pobrać ze strony Głównego Urzędu Statystycznego (GUS): Pliki pełne rejestru TERYT.

System identyfikatorów i nazw jednostek podziału terytorialnego TERC zawiera identyfikatory i nazwy jednostek zasadniczego trójstopniowego podziału terytorialnego kraju i jest zbudowany według hierarchicznej numeracji:
• województw,
• powiatów,
• gmin.
W systemie odrębnymi identyfikatorami wyróżniono:
• miasta na prawach powiatu,
• gminy miejskie, wiejskie, miejsko-wiejskie,
• miasta i obszary wiejskie w gminach miejsko-wiejskich,
• dzielnice i delegatury w gminach miejskich

Przetwarzanie pliku TERC.xml

Plik TERC.xml zawiera wykaz identyfikatorów i nazw jednostek podziału terytorialnego. Plik ten, został pobrany do bieżącego katalogu bazy danych, do folderu o nazwieTERYT. Na stronie Opis struktury zbioru TERC możemy zapoznać się ze strukturą tego pliku.

Opis struktury zbioru TERC
WOJ - symbol województwa - 2 zn. C
  • dwucyfrowy symbol województwa nadany województwom ułożonym w kolejności alfabetycznej z liczb parzystych w przedziale liczb 02 - 98.
POW - symbol powiatu - 2 zn. C
  • dwucyfrowy symbol powiatu nadany powiatom danego województwa, ułożonym w kolejności alfabetycznej, a następnie miastom na prawach powiatu, odpowiednio:
  • liczby 01 - 60 - oznaczają symbol powiatu,
  • liczby 61 - 99 - określają symbol miasta na prawach powiatu,
GMI - symbol gminy - 2 zn. C
  • dwie kolejne liczby w przedziale liczb 01 – 99, nadane gminom (dzielnicom, delegaturom) po ich ułożeniu w kolejności alfabetycznej w powiatach, począwszy od gmin miejskich, po nich w kolejności gminy wiejskie i miejsko-wiejskie,
RODZ (*) - symbol rodzaju jednostki - 1 zn. C
cyfra określająca symbol rodzaju jednostki:
1 - gmina miejska,
2 - gmina wiejska,
3 - gmina miejsko-wiejska,
4 - miasto w gminie miejsko-wiejskiej,
5 - obszar wiejski w gminie miejsko-wiejskiej,
8 - dzielnica w m.st. Warszawa,
9 - delegatury miast: Kraków, Łódź, Poznań i Wrocław
NAZWA - nazwa województwa / powiatu / gminy - 36 100 zn. C
NAZDOD NAZWA_DOD - określenie rodzaju jednostki: - 50 zn. C
Objaśnienia rodzaju niektórych jednostek objętych systemem:
  • gmina miejska, miasto stołeczne oznacza gminę o statusie miasta,
  • gmina wiejska – na jej terenie znajdują się wyłącznie wsie,
  • gmina miejsko-wiejska to jednostka, na terenie której jedna z miejscowości ma status miasta, a pozostały teren tej gminy stanowi jej obszar wiejski,
  • dzielnica – jednostka pomocnicza w m. st. Warszawa,
  • delegatura – dawna dzielnica w miastach: Kraków, Łódź, Poznań i Wrocław.
STAN_NA - data aktualizacji danych w systemie TERC w formacie RRRR-MM-DD - 10 zn. C

(*) - w opisie struktury zbioru SIMCULIC element nazwany zostanie: RODZ_GMI

 
Znak Uwaga No i ZONK!.
W wykazie plików predefiniowanych nie ma żadnego pliku *.xml zawierającego jednoznakowe (- 1 zn. C) zestawienie symboli rodzajów jednostek i ich nazwy opisowe.

Zestawienie symboli rodzajów jednostek.

Struktura tabeli tblRodz_Gmi.


Skoro w wykazie plików predefiniowanych nie ma żadnego pliku *.xml określającego symbole rodzajów jednostek ID_RG i ich nazwy opisowe tNazwa_RG, to musimy sami napisać funkcję zapisującą w tabeli symbole i ich nazwy opisowe w tabeli nazwie tblRodz_Gmi. Struktura tabeli przedstawiona jest poniżej:

Tabela tblRodz_Gmi - struktura
Nazwa pola *) Typ Rozmiar **) Wymagane Zerowa długość Uwagi
ID_RG Tekst 1 Tak Nie PrimaryKey
tNazwa_RG Tekst 41 100 Tak Nie  
tSkrot_RG Tekst 21 Tak Nie Dodatkowe pole

 

Znak Informacja dodatkowa Najdłuższa nazwa opisowa w polu tNazwa_RGobszar wiejski w gminie miejsko-wiejskiej” zawiera aż 41 znaków. Tak długa nazwa wymusza utworzenie bardzo szerokiego formantu, tak by zmieścił w całości cały tekst. By tego uniknąć, utworzę w tabeli tblRodz_Gmi dodatkowe pole tSkrot_RG o długości 21 znaków (nie wymagane przez strukturę danych w plikach *.xml), które zawierać będzie skróconą nazwę opisową symbolu rodzaju jednostki.

Tworzenie tabeli tblRodz_Gmi.

Tabelę tblRodz_Gmi możemy utworzyć korzystając z metod klasy clsTeryt opisanej na stronie: Klasa clsTeryt

Dim clsRodzGmi As clsTeryt
	Set clsRodzGmi = New clsTeryt
		With clsRodzGmi
			.terytDeleteTable "tblRodz_Gmi"
			.terytCreateTable "tblRodz_Gmi"
				.terytCreateField "ID_RG", dbText, 1
				.terytCreateField "tNazwa_RG", dbText, 100
				' dodatkowe, skrótowe pole opisowe
				.terytCreateField "tSkrot_RG", dbText, 21
			.terytAppendTable
			' utwórz Indeks Primary
			.terytCreateIndex "ID_RG", True
		End With
	Set clsRodzGmi = Nothing

Zapis symboli i nazwy rodzaju jednostek (gmin) do tabeli 'tblRodz_Gmi'

Public Function fRodzGmiToTable(sTblName As String) As Boolean
Dim dbs        As DAO.Database
Dim rst        As DAO.Recordset
Dim vRodzGmi   As Variant
Dim i          As Integer
Const cModule_Name   As String = "Function fRodzGmiToTable (...)"

On Error GoTo Err_Handler

	' każdy co trzeci element tablicy, to własna, skrótowa nazwa opisowa
	vRodzGmi = Array( _
							"1", "gmina miejska", "gmina miejska", _
							"2", "gmina wiejska", "gmina wiejska", _
							"3", "gmina miejsko-wiejska", "gmina miejsko-wiejska", _
							"4", "miasto w gminie miejsko-wiejskiej", "miasto", _
							"5", "obszar wiejski w gminie miejsko-wiejskiej", "obszar wiejski", _
							"8", "dzielnica w m.st. Warszawa", "dzielnica Warszawy", _
							"9", "delegatury miast: Kraków, Łódź, Poznań i Wrocław", "delegatura")

	 Set dbs = CurrentDb
	 Set rst = dbs.OpenRecordset(sTblName, dbOpenDynaset, dbAppendOnly)

		For i = LBound(vRodzGmi) To UBound(vRodzGmi) Step 3
			With rstRodzGmi
				.AddNew
					!Id_RG = vRodzGmi(i)
					!tNazwa_RG = vRodzGmi(i + 1)
					!tSkrot_RG = vRodzGmi(i + 2)
				.Update
			End With
		Next

	fRodzGmiToTable = True

Exit_Here:
	' zniszcz zmienne obiektowe
	If Not (rst Is Nothing) Then rst.Close
	Set rst = Nothing
	Set dbs = Nothing
Exit Function

Err_Handler:
	MsgBox "Błąd nr " & Err.Number & vbNewLine & _
					Err.Description & vbNewLine & _
					"Źródło: " & Err.Source & vbNewLine & _
					"Moduł: " & cModule_Name
	Resume Exit_Here

End Function

Struktura pliku TERC.xml

Ponieważ struktura pliku TERC.xml została zmieniona, funkcja przetwarzający plik TERC.xml musiała zostać dostosowana do obowiązującej struktury pliku (nazw zmienionych elementów) przetwarzanego pliku TERC.xml.

Jeżeli chodzi o tabele to zmiana dotyczy elementu [NAZWA] określającego nazwę województwa / powiatu / gminy, dla którego zwiększono ilość znaków z 36 do 100 znaków. W tabelach tblWojewodztwa, tblPowiaty, tblTERC_Gminy, należy zmienić rozmiar odpowiednich pól [tWojewodztwo], [tPowiat], [tNazwa] z 36 znaków na 100 znaków.

Ponieważ plik zawiera 4 167 elementów <row>, a każdy z nich zawiera 7 elementów <col> co daje w sumie 29 169 pojedynczych elementów, więc struktura pliku TERC.xml zostanie omówiona na przykładzie trzech pierwszych elementów <col> pliku TERC.xml.

Poniżej struktura starego pliku TERC.xml z dnia 2015-02-28 i struktura aktualnego pliku TERC.xml dla trzech pierwszych elementów <row> zbioru TERC.xml.

<?xml version="1.0" encoding="UTF-8"?>
<teryt>
  <catalog name="TERC" type="all" date="2015-01-01">
		<row>
			<col name="WOJ">02</col>
			<col name="POW"/>				
			<col name="GMI"/>				
			<col name="RODZ"/>
			<col name="NAZWA">DOLNOŚLĄSKIE</col>
			<col name="NAZDOD">województwo</col>
			<col name="STAN_NA">2015-01-01</col>
		</row>
		
		<row>
			<col name="WOJ">02</col>
			<col name="POW">01</col>						
			<col name="GMI"/>										
			<col name="RODZ"/>
			<col name="NAZWA">bolesławiecki</col>
			<col name="NAZDOD">powiat</col>
			<col name="STAN_NA">2015-01-01</col>
		</row>
		
		<row>
			<col name="WOJ">02</col>
			<col name="POW">01</col>
			<col name="GMI">01</col>
			<col name="RODZ">1</col>
			<col name="NAZWA">Bolesławiec</col>
			<col name="NAZDOD">gmina miejska</col>
			<col name="STAN_NA">2015-01-01</col>
		</row>
		

		

	</catalog>
</teryt>
<?xml version="1.0" encoding="UTF-8"?>
<teryt>
	<catalog name="TERC" type="ALL" date="2018-01-02">
		<row>
			<WOJ>02</WOJ>
			<POW />
			<GMI />
			<RODZ />
			<NAZWA>DOLNOŚLĄSKIE</NAZWA>
			<NAZWA_DOD>województwo</NAZWA_DOD>
			<STAN_NA>2018-01-02</STAN_NA>
		</row>
		
		<row>
			<WOJ>02</WOJ>
			<POW>01</POW>
			<GMI />
			<RODZ />
			<NAZWA>bolesławiecki</NAZWA>
			<NAZWA_DOD>powiat</NAZWA_DOD>
			<STAN_NA>2018-01-02</STAN_NA>
		</row>
		
		<row>
			<WOJ>02</WOJ>
			<POW>01</POW>
			<GMI>01</GMI>
			<RODZ>1</RODZ>
			<NAZWA>Bolesławiec</NAZWA>
			<NAZWA_DOD>gmina miejska</NAZWA_DOD>
			<STAN_NA>2018-01-02</STAN_NA>
		</row>
		

		

	</catalog>
</teryt>
Znając strukturę zbioru TERC musimy utworzyć trzy tabele na przyjęcie danych z pliku TERC.xml.
Będą to następujące tabele:
• tblWojewodztwa
• tblPowiaty
• tblGminy
Struktura tych tabel przedstawiona jest poniżej:
 

Struktura tabeli tblWojewodztwa.


Tabela tblWojewodztwa - struktura
Nazwa pola*) Typ Rozmiar**) Wymagane Zerowa długość Uwagi
ID_Woj Tekst 2 Tak Nie PrimaryKey
tWojewodztwo Tekst 36 100 Tak Nie  
tNazDod
tNazwa_Dod

Tekst

50

Tak

Nie
 

Tworzenie tabeli tblWojewodztwa.

Tabelę tblWojewodztwa możemy utworzyć korzystając z metod klasy clsTeryt ze strony: Klasa clsTeryt

Dim clsWoj As clsTeryt
  Set clsWoj = New clsTeryt
    With clsWoj
      .terytDeleteTable "tblWojewodztwa"
      .terytCreateTable "tblWojewodztwa"
        .terytCreateField "ID_Woj", dbText, 2
        .terytCreateField "tWojewodztwo", dbText, 100
        .terytCreateField "tNazwa_Dod", dbText, 50
      .terytAppendTable
      ' utwórz Indeks Primary
      .terytCreateIndex "ID_Woj", True
    End With
  Set clsWoj = Nothing

Struktura tabeli tblPowiaty.


Tabela tblPowiaty - struktura
Nazwa pola*) Typ Rozmiar**) Wymagane Zerowa długość Uwagi
ID_Pow Tekst 4 Tak Nie PrimaryKey
Id_Woj Tekst 2 Tak Nie Indeks. Duplikaty (OK)
tPowiat Tekst 36 100 Tak Nie  
tNazDod
tNazwa_Dod

Tekst

50

Tak

Nie
 
ID_Pow = jest połączeniem elementów <WOJ> & <POW> ze zbioru TERC

Tworzenie tabeli tblPowiaty.

Tabelę tblPowiaty możemy utworzyć korzystając z metod klasy clsTeryt opisanej na stronie: Klasa clsTeryt

Dim clsPow As clsTeryt
  Set clsPow = New clsTeryt
    With clsPow
    .terytDeleteTable "tblPowiaty"
    .terytCreateTable "tblPowiaty"
      .terytCreateField "ID_Pow", dbText, 4
      .terytCreateField "Id_Woj", dbText, 2
      .terytCreateField "tPowiat", dbText, 100
      .terytCreateField "tNazwa_Dod", dbText, 50
    .terytAppendTable
    ' utwórz Indeks Primary
    .terytCreateIndex "ID_Pow", True
    ' utwórz Indeks (duplikaty OK)
    .terytCreateIndex "Id_Woj"
    End With
  Set clsPow = Nothing

Struktura tabeli tblTERC_Gminy.


Tabela tblTERC_Gminy - struktura
Nazwa pola*) Typ Rozmiar**) Wymagane Zerowa długość Uwagi
ID_Gmi Tekst 7 Tak Nie PrimaryKey
Id_Pow Tekst 4 Tak Nie Indeks. Duplikaty (OK)
Id_RG Tekst 1 Tak Nie Indeks. Duplikaty (OK)
tNazwa Tekst 36 100 Tak Nie  
tNazDod
tNazwa_Dod

Tekst

50

Tak

Nie
 
tStan_Na Tekst 10 Tak Nie  
ID_Gmi = jest połączeniem elementów: <WOJ> & <POW> & <GMI> & <RODZ> ze zbioru TERC
Id_Pow = jest połączeniem elementów <WOJ> & <POW> ze zbioru TERC

Tworzenie tabeli tblTERC_Gminy.

Tabelę tblTERC_Gminy możemy utworzyć korzystając z metod klasy clsTeryt opisanej na stronie: Klasa clsTeryt

Dim clsTERC As clsTeryt
  Set clsTERC = New clsTeryt
    With clsTERC
      .terytDeleteTable "tblTERC_Gminy"
      .terytCreateTable "tblTERC_Gminy"
        .terytCreateField "ID_Gmi", dbText, 7
        .terytCreateField "Id_Pow", dbText, 4
        .terytCreateField "Id_RG", dbText, 1
        .terytCreateField "tNazwa", dbText, 100
        .terytCreateField "tNazwa_Dod", dbText, 50
        .terytCreateField "tStan_Na", dbText, 10
      .terytAppendTable
      ' utwórz Indeks Primary
      .terytCreateIndex "ID_Gmi", True
      ' utwórz Indeksy (duplikaty OK)
      .terytCreateIndex "Id_Pow"
      .terytCreateIndex "Id_RG"
    End With
  Set clsTERC = Nothing

 

Uwagi dodatkowe.
Dotyczą wszystkich tabel na tej stronie.
*)   - Dla pola będącego kluczem głównym, stosuję prefiks „ID_”,
      - Klucz obcy zawsze poprzedzam prefiksem „Id_”
      - Nazwy pól nie będące kluczem głównym i kluczem obcym poprzedzam prefiksem „t
**) Minimalna długość pola. Można użyć większego rozmiaru pola.
       MS Access nie dopełnia pól tekstowych do zadeklarowanej długości.

Po utworzeniu w/w tabel, możemy pobrać dane z pliku TERC.xml i zapisać je do tych tabel. Jak to zrobić? Po prostu skorzystać z gotowej funkcji:

Public Function fXmlTercToTable( _
			ByVal sFileXmlPath As String, _
			ByVal sTblTerc As String, _
			ByVal sTblWojewodztwo As String, _
			ByVal sTblPowiat As String) As Boolean
			
przedstawionej na poniższym „listingu”:
' Nieaktualna funkcja wczytująca dane z pliku TERC.xml do tabel MS Access
Public Function fXmlTercToTable( _
                  ByVal sFileXmlPath As String, _
                  ByVal sTblTerc As String, _
                  ByVal sTblWojewodztwo As String, _
                  ByVal sTblPowiat As String) As Boolean
#If pbl_fEarly = True Then
  Dim xmlDoc        As MSXML2.DOMDocument60
  Dim oNodes        As MSXML2.IXMLDOMNodeList
  Dim oWOJ          As MSXML2.IXMLDOMNodeList
  Dim oPOW          As MSXML2.IXMLDOMNodeList
  Dim oGMI          As MSXML2.IXMLDOMNodeList
  Dim oRODZ         As MSXML2.IXMLDOMNodeList
  Dim oNAZWA        As MSXML2.IXMLDOMNodeList
  Dim oNAZDOD       As MSXML2.IXMLDOMNodeList
  Dim oSTAN_NA      As MSXML2.IXMLDOMNodeList
#Else
  Dim xmlDoc        As Object
  Dim oNodes        As Object
  Dim oWOJ          As Object
  Dim oPOW          As Object
  Dim oGMI          As Object
  Dim oRODZ         As Object
  Dim oNAZWA        As Object
  Dim oNAZDOD       As Object
  Dim oSTAN_NA      As Object
#End If

Dim sXPath          As String
Dim i               As Integer
Const cParser_XML   As String = "MSXML2.DOMDocument"

Dim dbs             As DAO.Database
Dim rstGminy        As DAO.Recordset
Dim rstWoj          As DAO.Recordset
Dim rstPow          As DAO.Recordset

Const cModule_Name  As String = "Function fXmlTercToTable (...)"

On Error GoTo Err_Handler

  ' Utwórz obiekt analizatora składni XML (parsera XML)
  #If pbl_fEarly = True Then
    ' Wczesne wiązanie (early binding)
     Set xmlDoc = New MSXML2.DOMDocument60
  #Else
    ' Późne wiązanie (late binding)
    Set xmlDoc = CreateObject("MSXML2.DOMDocument")
  #End If

  With xmlDoc
    .Load (sFileXmlPath)

    ' sprawdź poprawność wczytanego XML'a
    If (.parseError.errorCode <> 0) Then
      Err.Raise .parseError.errorCode, cParser_XML, .parseError.reason
    End If

    ' utwórz adres do elementów <row>
    sXPath = "/teryt/catalog/row"

    Set oWOJ = .SelectNodes(sXPath & "/col[@name='WOJ']")
    Set oPOW = .SelectNodes(sXPath & "/col[@name='POW']")
    Set oGMI = .SelectNodes(sXPath & "/col[@name='GMI']")
    Set oRODZ = .SelectNodes(sXPath & "/col[@name='RODZ']")
    Set oNAZWA = .SelectNodes(sXPath & "/col[@name='NAZWA']")
    Set oNAZDOD = .SelectNodes(sXPath & "/col[@name='NAZDOD']")
    Set oSTAN_NA = .SelectNodes(sXPath & "/col[@name='STAN_NA']")
    Set oNodes = .SelectNodes(sXPath)

  End With

  Set dbs = CurrentDb
  Set rstWoj = dbs.OpenRecordset(sTblWojewodztwo, dbOpenDynaset, dbAppendOnly)
  Set rstPow = dbs.OpenRecordset(sTblPowiat, dbOpenDynaset, dbAppendOnly)
  Set rstGminy = dbs.OpenRecordset(sTblTerc, dbOpenDynaset, dbAppendOnly)

  ' przejdź po wszystkich elementach <row> i zapisz wartości elementów <col> do tabeli
  For i = 0 To oNodes.length - 1
    ' jeżeli element <POW> i <GMI> nie zawierają danych, zapisz ID_Woj,
    ' jego nazwę oraz nazwę dodatkową
    If Len(oPOW(i).Text) = 0 And Len(oGMI(i).Text) = 0 Then
      With rstWoj
        .AddNew
          !Id_Woj = oWOJ(i).Text
          !tWojewodztwo = oNAZWA(i).Text
          !tNazDod = oNAZDOD(i).Text
        .Update
      End With

    ' jeżeli element <GMI> nie zawiera danych
    ' zapisz ID Powiatu, Id Województwa, nazwę Powiatu i nazwę dodatkową
    ElseIf Len(oGMI(i).Text) = 0 Then
      With rstPow
        .AddNew
          !Id_Pow = oWOJ(i).Text & oPOW(i).Text
          !Id_Woj = oWOJ(i).Text
          !tPowiat = oNAZWA(i).Text
          !tNazDod = oNAZDOD(i).Text
        .Update
      End With
    Else

      ' zapisz identyfikator Gminy, Powiatu, symbol rodzaju jednostki,
      ' nazwę Gminy i jej nazwę dodatkową oraz datę aktualizacji
      With rstGminy
        .AddNew
          !ID_Gmi = oWOJ(i).Text & oPOW(i).Text & oGMI(i).Text &  oRODZ(i).Text
          !Id_Pow = oWOJ(i).Text & oPOW(i).Text
          !Id_RG = oRODZ(i).Text
          !tNazwa = oNAZWA(i).Text
          !tNazDod = oNAZDOD(i).Text
          !tStan_Na = oSTAN_NA(i).Text
        .Update
      End With
    End If
  Next

  fXmlTercToTable = True

Exit_Here:
    ' zniszcz zmienne obiektowe
    If Not (rstWoj Is Nothing) Then rstWoj.Close
    If Not (rstPow Is Nothing) Then rstPow.Close
    If Not (rstGminy Is Nothing) Then rstGminy.Close

    Set rstWoj = Nothing
    Set rstPow = Nothing
    Set rstGminy = Nothing
    Set dbs = Nothing

    Set oWOJ = Nothing
    Set oPOW = Nothing
    Set oGMI = Nothing
    Set oRODZ = Nothing
    Set oNAZWA = Nothing
    Set oNAZDOD = Nothing
    Set oSTAN_NA = Nothing
    Set oNodes = Nothing
    Set xmlDoc = Nothing
  Exit Function

Err_Handler:
  MsgBox "Błąd nr " & Err.Number & vbNewLine & _
          Err.Description & vbNewLine & _
          "Źródło: " & Err.Source & vbNewLine & _
          "Moduł: " & cModule_Name
  Resume Exit_Here

End Function

Funkcja wczytująca dane z pliku TERC.xml do tabel MS Access

• Stan na dzień 03 marca 2018 roku

Public Function fXmlTercToTable( _
                  ByVal sFileXmlPath As String, _
                  ByVal sTblTerc As String, _
                  ByVal sTblWojewodztwo As String, _
                  ByVal sTblPowiat As String) As Boolean
#If pbl_fEarly = True Then
  Dim xmlDoc        As MSXML2.DOMDocument60
  Dim oNodes        As MSXML2.IXMLDOMNodeList
  Dim oWOJ          As MSXML2.IXMLDOMNodeList
  Dim oPOW          As MSXML2.IXMLDOMNodeList
  Dim oGMI          As MSXML2.IXMLDOMNodeList
  Dim oRODZ         As MSXML2.IXMLDOMNodeList
  Dim oNAZWA        As MSXML2.IXMLDOMNodeList
  Dim oNAZWA_DOD    As MSXML2.IXMLDOMNodeList
  Dim oSTAN_NA      As MSXML2.IXMLDOMNodeList
#Else
  Dim xmlDoc        As Object
  Dim oNodes        As Object
  Dim oWOJ          As Object
  Dim oPOW          As Object
  Dim oGMI          As Object
  Dim oRODZ         As Object
  Dim oNAZWA        As Object
  Dim oNAZWA_DOD    As Object
  Dim oSTAN_NA      As Object
#End If

Dim sXPath          As String
Dim i               As Integer
Const cParser_XML   As String = "MSXML2.DOMDocument"

Dim dbs             As DAO.Database
Dim rstGminy        As DAO.Recordset
Dim rstWoj          As DAO.Recordset
Dim rstPow          As DAO.Recordset

Const cModule_Name  As String = "Function fXmlTercToTable (...)"

On Error GoTo Err_Handler

  ' Utwórz obiekt analizatora składni XML (parsera XML)
  #If pbl_fEarly = True Then
    ' Wczesne wiązanie (early binding)
     Set xmlDoc = New MSXML2.DOMDocument60
  #Else
    ' Późne wiązanie (late binding)
    Set xmlDoc = CreateObject("MSXML2.DOMDocument")
  #End If

  With xmlDoc
    .Load (sFileXmlPath)

    ' sprawdź poprawność wczytanego XML'a
    If (.parseError.errorCode <> 0) Then
      Err.Raise .parseError.errorCode, cParser_XML, .parseError.reason
    End If

    ' utwórz adres do elementów <row>
    sXPath = "/teryt/catalog/row"

    Set oWOJ = .selectNodes(sXPath & "/WOJ")
    Set oPOW = .selectNodes(sXPath & "/POW")
    Set oGMI = .selectNodes(sXPath & "/GMI")
    Set oRODZ = .selectNodes(sXPath & "/RODZ")
    Set oNAZWA = .selectNodes(sXPath & "/NAZWA")
    'Set oNAZDOD = .selectNodes(sXPath & "/NAZDOD")
    Set oNAZWA_DOD = .selectNodes(sXPath & "/NAZWA_DOD")
    Set oSTAN_NA = .selectNodes(sXPath & "/STAN_NA")
    ' ustaw zmienną obiektową odnosząca się do wszystkich elementów <row>
    Set oNodes = .selectNodes(sXPath)

  End With

  Set dbs = CurrentDb
  Set rstWoj = dbs.OpenRecordset(sTblWojewodztwo, dbOpenDynaset, dbAppendOnly)
  Set rstPow = dbs.OpenRecordset(sTblPowiat, dbOpenDynaset, dbAppendOnly)
  Set rstGminy = dbs.OpenRecordset(sTblTerc, dbOpenDynaset, dbAppendOnly)

  ' przejdź po wszystkich elementach <row> i zapisz wartości poszczególnych elementów do tabeli
  For i = 0 To oNodes.Length - 1
    ' jeżeli element <POW> i <GMI> nie zawierają danych, zapisz ID_Woj,
    ' jego nazwę i nazwę dodatkową
    If Len(oPOW(i).Text) = 0 And Len(oGMI(i).Text) = 0 Then
      With rstWoj
        .AddNew
          !Id_Woj = oWOJ(i).Text
          !tWojewodztwo = oNAZWA(i).Text
          !tNazwa_Dod = oNAZWA_DOD(i).Text
        .Update
      End With

    ' jeżeli element <GMI> nie zawiera danych
    ' zapisz ID Powiatu, Id Województwa, nazwę Powiatu i nazwę dodatkową
    ElseIf Len(oGMI(i).Text) = 0 Then
      With rstPow
        .AddNew
          !ID_Pow = oWOJ(i).Text & oPOW(i).Text
          !Id_Woj = oWOJ(i).Text
          !tPowiat = oNAZWA(i).Text
          !tNazwa_Dod = oNAZWA_DOD(i).Text
        .Update
      End With
    Else

      ' zapisz identyfikator Gminy, Powiatu, symbol rodzaju jednostki,
      ' nazwę Gminy i jej nazwę dodatkową oraz datę aktualizacji
      With rstGminy
        .AddNew
          !ID_Gmi = oWOJ(i).Text & oPOW(i).Text & oGMI(i).Text & oRODZ(i).Text
          !ID_Pow = oWOJ(i).Text & oPOW(i).Text
          !ID_RG = oRODZ(i).Text
          !tNazwa = oNAZWA(i).Text
          !tNazwa_Dod = oNAZWA_DOD(i).Text
          !tStan_Na = oSTAN_NA(i).Text
        .Update
      End With
    End If
  Next

  fXmlTercToTable = True

Exit_Here:
    ' zniszcz zmienne obiektowe
    If Not (rstWoj Is Nothing) Then rstWoj.Close
    If Not (rstPow Is Nothing) Then rstPow.Close
    If Not (rstGminy Is Nothing) Then rstGminy.Close

    Set rstWoj = Nothing
    Set rstPow = Nothing
    Set rstGminy = Nothing
    Set dbs = Nothing

    Set oWOJ = Nothing
    Set oPOW = Nothing
    Set oGMI = Nothing
    Set oRODZ = Nothing
    Set oNAZWA = Nothing
    Set oNAZWA_DOD = Nothing
    Set oSTAN_NA = Nothing
    Set oNodes = Nothing
    Set xmlDoc = Nothing
  Exit Function

Err_Handler:
  MsgBox "Błąd nr " & Err.Number & vbNewLine & _
          Err.Description & vbNewLine & _
          "Źródło: " & Err.Source & vbNewLine & _
          "Moduł: " & cModule_Name
  Resume Exit_Here

End Function
 
Znak Uwaga No i znowu prześliczny ZONK!.
MS Access generuje błąd wykonania numer 91.
Błąd pliku TERC nr 91

Popatrzmy na opis struktury pliku TERC.xml na stronie: Opis struktury zbioru TERC

Opis struktury TERC
Fragment zrzutu ekranowego strony „Rejestr TERYT. Pliki pełne - struktury”.

 

Element NAZWA_DOD struktury TERC
Obecna struktura pliku TERC.xml                 Dawna struktura pliku TERC.xml

 

Znak Uwaga Według osoby opisującej strukturę pliku element nazywa się NAZDOD, (taka była nazwa w starym pliku). W nowym pliku element nazwano NAZWA_DOD no i przez niedopatrzenie powstał ten piękny ZONK!

 

Tyle gadania o nic. Po prostu użytkownik końcowy zmienia sobie w tabeli tblTERC_Gminy nazwę pola tNazDod na tNazwa_Dod (chociaż ta zmiana nie jest konieczna) ale koniecznie rozmiar pola na 100 znaków.

' Jeszcze tylko drobna poprawka w kodzie.
' Linijkę:
Set oNAZDOD = .selectNodes(sXPath & "/NAZDOD")
' należy zmienić na
Set oNAZWA_DOD = .selectNodes(sXPath & "/NAZWA_DOD")

Potem to już z górki (wedle trzech buczków), użytkownik zmienia jedną linijkę kodu w której występuje odwołanie  do wadliwego elementu struktury pliku TERC.xml i po krzyku.
No i po co tyle gadania. Przecież przysłowiowa p. Marysia z takimi pierdołami da sobie radę w przerwie między kawami.
A jak sobie nie da rady to są tacy, co będą z tego bardzo zadowoleni:
200 zł za godzinę, a za każdy rozpoczęty kwadrans 50 zł

Ad rem.

Szybkość przetwarzania pliku TERC.xml

Jak na razie, nie ma się chyba do czego przyczepić. Czas przetwarzania i zapisu do tabel danych przez funkcję fXmlTercToTable (...), pliku TERC.xml wielkości 1 MB, zawierającego ok. 30 000 elementarnych danych w ponad 4 000 rekordach wynosi:

  • ok. 2,5 sekundy dla „wczesnego wiązania”
  • ok. 3,0 sekundy dla „późnego wiązania”.

Zapewne można by trochę przyspieszyć funkcję, nie tworząc dla każdego elementu zawartego w elemencie <row> zmiennych obiektowych przechowującej kolekcję wszystkich elementów.
Być może, tak zrobię przy przetwarzaniu pliku SIMC.xml.