Access

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

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

WMRODZ (wykaz symboli i nazw rodzajów miejscowości)

• Stan na dzień 03 marca 2018 roku

Plik WMRODZ.xml zawiera wykaz rodzajów miejscowości i ich identyfikatorów. Zbiór WMRODZ powinien być przetwarzany razem ze zbiorem SIMC zawierającym identyfikatory i nazwy miejscowości.

Plik ten, jak i pozostałe pliki Rejestru TERYT, można pobrać ze strony Głównego Urzędu Statystycznego (GUS): Pliki pełne rejestru TERYT. Pliki powinny być pobrane do bieżącego katalogu bazy danych, do folderu o nazwie TERYT.

Wykaz rodzajów miejscowości i ich identyfikatorów WMRODZ zawiera:
• symbol rodzaju miejscowości
• nazwę rodzaju miejscowości.
• datę aktualizacji danych w podsystemie WMRODZ w formacie RRRR-MM-DD.

Przetwarzanie pliku WMRODZ.xml

Plik WMRODZ.xml zawiera wykaz rodzajów miejscowości i ich symbole. Na stronie Opis struktury zbioru WMRODZ możemy zapoznać się ze strukturą tego pliku, która przedstawiona jest poniżej
wg stanu na dzień 2018-03-01:

Opis struktury zbioru WMRODZ
RM - symbol rodzaju miejscowości - 2 zn. C
NAZWA_RM - nazwa rodzaju miejscowości - 24 100 zn. C
STAN_NA - data danych w formacie RRRR-MM-DD - 10 zn. C
Symbole i nazwy rodzajów miejscowości:
00 - część miejscowości
01 - wieś
02 - kolonia
03 - przysiółek
04 - osada
05 - osada leśna
06 - osiedle
07 - schronisko turystyczne
95 - dzielnica m. st. Warszawy
96 - miasto
98 - delegatura
99 - część miasta

Gdybyśmy porównali strukturę pliku WMRODZ.xml z dnia 2013-02-28 ze strukturą pliku aktualnego, to zaszły pewne zmiany. Chyba symbol rodzaju miejscowości RM = 95 zmienił brzmienie z błędnie wpisanej „dzielnica m.st. Warszawy” zamiast ' m.st. ' na pojedyncze określenie: dzielnica. Piszę „chyba zmienił brzmienie”, gdyż na stronie Ogólna charakterystyka systemów rejestru zakładka SIMC/SYSTEM IDENTYFIKATORÓW I NAZW MIEJSCOWOŚCI (SIMC), możemy przeczytać:

Obecnie w katalogu miejscowości funkcjonuje 12 określeń rodzajowych, którym nadano dwucyfrowe symbole:
00 część miejscowości
...
dzielnica m.st. Warszawy (tutaj jednak ze spacją)
...
99 część miasta

Struktura pliku WMRODZ.xml

Poniżej struktura starego pliku WMRODZ.xml z dnia 2013-02-28 i struktura aktualnego pliku WMRODZ.xml. Ponieważ struktura pliku WMRODZ.xml została zmieniona, funkcja przetwarzający plik WMRODZ.xml musiała zostać dostosowana do obowiązującej struktury pliku (nazw zmienionych elementów) przetwarzanego pliku WMRODZ.xml.

Rozmiar elementu [NAZWA_RM] (nazwa rodzaju miejscowości) został zwiększony z 24 znaków do 100 znaków, należy więc w  tabeli tblWMRodz, zmienić rozmiar pola tNazwa_RM z 24 znaków na 100 znaków.

		<?xml version="1.0" encoding="UTF-8"?>
		<teryt>
			<catalog name="SIMC" type="all" date="2013-02-28">
				<row>
					<col name="RM">01</col>
					<col name="NAZWA_RM">wieś</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">02</col>
					<col name="NAZWA_RM">kolonia</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">03</col>
					<col name="NAZWA_RM">przysiółek</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">04</col>
					<col name="NAZWA_RM">osada</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">05</col>
					<col name="NAZWA_RM">osada leśna</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">06</col>
					<col name="NAZWA_RM">osiedle</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">07</col>
					<col name="NAZWA_RM">schronisko turystyczne </col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">95</col>
					<col name="NAZWA_RM">dzielnica m. st. Warszawy</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">96</col>
					<col name="NAZWA_RM">miasto</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">98</col>
					<col name="NAZWA_RM">delegatura</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
				<row>
					<col name="RM">99</col>
					<col name="NAZWA_RM">część miasta</col>
					<col name="STAN_NA">2013-02-28</col>
					</row>
				<row>
					<col name="RM">00</col>
					<col name="NAZWA_RM">część miejscowości</col>
					<col name="STAN_NA">2013-02-28</col>
				</row>
			</catalog>
		</teryt>
		
<?xml version="1.0" encoding="utf-8"?>
<SIMC>
  <catalog name="SIMC" type="ALL" date="2013-02-28">
    <row>
      <RM>00</RM>
      <NAZWA_RM>część</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>01</RM>
      <NAZWA_RM>wieś</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>02</RM>
      <NAZWA_RM>kolonia</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>03</RM>
      <NAZWA_RM>przysiółek</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>04</RM>
      <NAZWA_RM>osada</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>05</RM>
      <NAZWA_RM>osada leśna</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>06</RM>
      <NAZWA_RM>osiedle</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>07</RM>
      <NAZWA_RM>schronisko turystyczne</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>95</RM>
      <NAZWA_RM>dzielnica</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>96</RM>
      <NAZWA_RM>miasto</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>98</RM>
      <NAZWA_RM>delegatura</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
    <row>
      <RM>99</RM>
      <NAZWA_RM>część miasta</NAZWA_RM>
      <STAN_NA>2013-02-28</STAN_NA>
    </row>
  </catalog>
</SIMC>
		

Struktura tabeli tblWMRodz.


Znając strukturę zbioru WMRODZ musimy utworzyć tabelę na przyjęcie danych z pliku WMRODZ.xml. Struktura tabeli przedstawiona jest poniżej:

Tabela tblWMRodz - struktura
Nazwa pola*) Typ Rozmiar**) Wymagane Zerowa długość Uwagi
ID_RM Tekst 2 Tak Nie PrimaryKey
tNazwa_RM Tekst 24 100 Tak Nie  
tStan_Na Tekst 10 Tak Nie  

 

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.

Tworzenie tabeli tblWMRodz.

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

Dim clsWMRodz As clsTeryt
  Set clsWMRodz = New clsTeryt
    With clsWMRodz
      .terytDeleteTable "tblWMRodz"
      .terytCreateTable "tblWMRodz"
        .terytCreateField "ID_RM", dbText, 2
        .terytCreateField "tNazwa_RM", dbText, 100
        .terytCreateField "tStan_Na", dbText, 10
      .terytAppendTable
      ' utwórz Indeks Primary
      .terytCreateIndex "ID_RM", True
    End With
  Set clsWMRodz = Nothing

Skoro mamy już tabelę, to musimy pobrać dane z pliku WMRODZ.xml i zapisać je do nowo utworzonej tabeli.
Jak to zrobić ? Po prostu korzystając z  analizatora składni XML firmy Microsoft (MSXML) napisać własną funkcję przetwarzającą plik WMRODZ.xml i zapisującą dane do tabeli. Ale najpierw kilka słów o odwołaniu się do „parsera MSXML”.

Analizator składni XML firmy Microsoft (MSXML)

Plik WMRODZ.xml i pozostałe Pliki pełne rejestru TERYT (*.xml) przetwarzać będziemy za pomocą obiektu spełniającego funkcję analizatora składni XML firmy Microsoft (MSXML), który można prościej określić mianem „parsera XML”. Parser MSXML jest zawarty w pliku msxml6.dll, który jako zgodny z mechanizmem Automatyzacji udostępnia interfejs, który umożliwia wykorzystanie Automatyzacji do komunikowania się z naszą bazą danych. Interfejs ten nigdy nie jest widoczny w samej aplikacji - dostęp do niego można uzyskać tylko w kodzie VBA, który łączy się z interfejsem i korzysta z udostępnianych zasobów.

Aby uzyskać dostęp do obiektów, metod i właściwości analizatora składni XML firmy Microsoft (MSXML) możemy wykorzystać „wczesne wiązanie” (ang. early binding) lub „późne wiązanie” (ang. late binding).

Wczesne wiązanie (ang. early binding) biblioteki Microsoft XML,v6.0.

W przypadku „wczesnego wiązania”musimy utworzyć odwołanie do biblioteki obiektów poprzez wybranie polecenia „Tools/References” w edytorze Visual Basic. W otwartym oknie dialogowym „References” należy znaleźć bibliotekę Microsoft XML,v6.0 i zaznaczyć pole wyboru.

Odwołanie do Microsoft XML,v6.0

Mając dodane odwołanie do biblioteki Microsoft XML,v6.0, możemy zadeklarować zmienną obiektową xmlDoc typu MSXML2.DOMDocument60 i przypisać utworzony egzemplarz obiektu klasy MSXML2.DOMDocument60 do zmiennej xmlDoc:

Dim xmlDoc As MSXML2.DOMDocument60
Set xmlDoc = New MSXML2.DOMDocument60

Późne wiązanie (ang. late binding) Microsoft XML,v6.0.

Jeżeli nie określimy odwołania („Reference”) do biblioteki Microsoft XML,v6.0, to aby odwołać się do tego obiektu musimy zadeklarować zmienną jako typ Object i wykorzystując instrukcję Set w połączeniu z metodą CreateObject, ustawić odwołanie zmiennej obiektowej na nowy egzemplarza obiektu bibliotecznego.

Dim xmlDoc As Object
Set xmlDoc = CreateObject("MSXML2.DOMDocument")

W przypadku gdy nie ma określonego obiektu bibliotecznego na lokalnym komputerze wystąpi błąd wykonania:

Odwołanie do Microsoft XML,v6.0

Aktualizacja funkcji własnej fXmlWMRodzToTable(...)

W porównaniu do struktury pliku WMRODZ.xml z dnia 28 lutego 2013 roku nastąpiła zmiana struktury, a raczej nazw elementów struktury tego pliku (i chyba pozostałych plików). Po tych zmianach aktualizacji musi ulec również funkcja fXmlWMRodzToTable(...). Na szczęście został wyeliminowany błąd, pojawiający się przy próbie wczytania danych z pliku WMRODZ.xmldo tabeli. MS Access zgłasza błąd:

Błąd wczytywania danych

wynikający z błędnego zapisu elementu [NAZWA_RM] = 'dzielnica m.st. Warszawy', W opisie struktury zbioru WMRODZ było: [NAZWA_RM] - nazwa rodzaju miejscowości - 24 zn. C, a w rzeczywistości element [NAZWA_RM] zawierał 25 znaków. Obecnie element [NAZWA_RM] powinien mieć wielkość 100 znaków, a symbol rodzaju miejscowości [RM] = 95 zmienił brzmienie na 'dzielnica'

' Funkcja ta jest nieaktualna. Patrz listing w następnym akapicie.
Public Function fXmlWMRodzToTable_Old( _
                    ByVal sFileXmlPath As String, _
                    ByVal sTblName As String) As Boolean
#If pbl_fEarly = True Then
  Dim xmlDoc        As MSXML2.DOMDocument60
  Dim oRM           As MSXML2.IXMLDOMNodeList
  Dim oNAZWA_RM     As MSXML2.IXMLDOMNodeList
  Dim oSTAN_NA      As MSXML2.IXMLDOMNodeList
  Dim oNodes        As MSXML2.IXMLDOMNodeList
#Else
  Dim xmlDoc        As Object
  Dim oRM           As Object
  Dim oNAZWA_RM     As Object
  Dim oSTAN_NA      As Object
  Dim oNodes        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 rstRM           As DAO.Recordset
Const cModule_Name  As String = "Function fXmlWMRodzToTable_Old (...)"

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)


    ' poprawka na zbyt długi (25 znakowy) element NAZWA_RM = "dzielnica m. st. Warszawy"
    ' pobierz .xml jako ciąg znaków, zastąp w nim pierwsze wystąpienie ciągu: " m. st. "
    ' na " m.st. " i ponownie załaduj metodą .loadXML obiektu "MSXML2.DOMDocument"
    ' Uwaga. Ważna jest wielkość liter !
    .loadXML Replace(.xml, " m. st. ", " m.st. ", 1, 1, vbBinaryCompare)


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

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

    ' ustaw zmienną obiektową odnoszącą się do elementów <col> o nazwie: "RM"
    Set oRM = .SelectNodes(sXPath & "/col[@name='RM']")

    ' ustaw zmienną obiektową odnoszącą się do elementów <col> o nazwie: "NAZWA_RM"
    Set oNAZWA_RM = .SelectNodes(sXPath & "/col[@name='NAZWA_RM']")

    ' ustaw zmienną obiektową odnoszącą się do elementów <col> o nazwie: "STAN_NA"
    Set oSTAN_NA = .SelectNodes(sXPath & "/col[@name='STAN_NA']")

    ' ustaw zmienną obiektową odnosząca się do wszystkich elementów <row>
    Set oNodes = .SelectNodes(sXPath)
  End With

  ' utwórz zmienną obiektową do bieżącej bazy danych
  Set dbs = CurrentDb

  ' otwórz rekordset oparty na tabeli odnoszącej się do WMRODZ.xml
  Set rstRM = dbs.OpenRecordset(sTblName, dbOpenDynaset, dbAppendOnly)

    ' przejdź po wszystkich elementach <row> i zapisz wartości elementów <col> do tabeli
    For i = 0 To oNodes.length - 1
      With rstRM
        .AddNew
          !ID_RM = oRM(i).Text
          !tNazwa_RM = oNAZWA_RM(i).Text
          !tStan_Na = oSTAN_NA(i).Text
        .Update
      End With
    Next

  fXmlWMRodzToTable_Old = True

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

    Set oRM = Nothing
    Set oNAZWA_RM = 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 WMRODZ.xml do tabeli MS Access

• Stan na dzień 03 marca 2018 roku

Public Function fXmlWMRodzToTable( _
                    ByVal sFileXmlPath As String, _
                    ByVal sTblName As String) As Boolean
#If pbl_fEarly = True Then
  Dim xmlDoc        As MSXML2.DOMDocument60
  Dim oRM           As MSXML2.IXMLDOMNodeList
  Dim oNAZWA_RM     As MSXML2.IXMLDOMNodeList
  Dim oSTAN_NA      As MSXML2.IXMLDOMNodeList
  Dim oNodes        As MSXML2.IXMLDOMNodeList
#Else
  Dim xmlDoc        As Object
  Dim oRM           As Object
  Dim oNAZWA_RM     As Object
  Dim oSTAN_NA      As Object
  Dim oNodes        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 rstRM           As DAO.Recordset
Const cModule_Name  As String = "Function fXmlWMRodzToTable (...)"

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 xmlDoc.parseError.errorCode, cParser_XML, xmlDoc.parseError.reason
    End If

    ' utwórz adres do elementu <row>
    sXPath = "/SIMC/catalog/row"

    ' ustaw zmienną obiektową odnoszącą się do elementów o nazwie: "RM"
    Set oRM = .selectNodes(sXPath & "/RM")

    ' ustaw zmienną obiektową odnoszącą się do elementów  o nazwie: "NAZWA_RM"
    Set oNAZWA_RM = .selectNodes(sXPath & "/NAZWA_RM")

    ' ustaw zmienną obiektową odnoszącą się do elementów o nazwie: "STAN_NA"
    Set oSTAN_NA = .selectNodes(sXPath & "/STAN_NA")

    ' ustaw zmienną obiektową odnosząca się do wszystkich elementów <row>
    Set oNodes = .selectNodes(sXPath)
  End With

  ' utwórz zmienną obiektową do bieżącej bazy danych
  Set dbs = CurrentDb

  ' otwórz rekordset oparty na tabeli odnoszącej się do pliku WMRODZ.xml
  Set rstRM = dbs.OpenRecordset(sTblName, dbOpenDynaset, dbAppendOnly)

    ' przejdź po wszystkich elementach <row> i zapisz wartości poszczególnych elementów do tabeli
    For i = 0 To oNodes.Length - 1
      With rstRM
        .AddNew
          !ID_RM = oRM(i).Text
          !tNazwa_RM = oNAZWA_RM(i).Text
          !tStan_Na = oSTAN_NA(i).Text
        .Update
      End With
    Next

  fXmlWMRodzToTable = True

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

    Set oRM = Nothing
    Set oNAZWA_RM = 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