Webcity.pl


  Programowanie obiekt...

  Programowanie obiekt...

  Open Power Template ...

  Wywiad z Wembzz /Inv...

  [tutorial] Realistyc...

 

 02.02.06 - [new] E-video - artykuł

 30.01.06 - [update] Artykuł o sesjach

 18.12.05 - [update] PDO - artykuł

 19.08.05 - [new+upd] Aktualizacja materia...

 26.04.05 - [update] Nowy artykuł



  Pomocy WML
[php]Sesje nie działają, ...
[actionscript 2.0] [flash...
Problem z talicami w php
[ocena] llll.pl darmowe a...
Kamera na stronie interne...
Kamera na stronie interne...
[xml] Jak wyciągnąć dane
Wizualizacja w JS - POMOC
Web Developer - stała / f...

... i wiele innych wątków na forum ›

Partnerzy
› allRSS.info - katalog zasobów RSS
› iloveflyer.org - webdesign
› webserv.pl - serverpack
› skryptoteka.pl - mnóstwo skryptów
› vel.pl - hosting
› TelePraca.net - pracuj swobodnie
› PHP Solutions - magazyn PHP
› HELION - wydawnictwo informatyczne

Ksišżka dnia

CityMag
Wpisz swój e-mail, aby zaprenumerować nasz Magazyn, który zawiera najnowsze informacje ze świata i najciekawsze teksty.
 

Szukasz czegoś?
Nasza wyszukiwarka znajdzie wszystko, czego szukasz.
 

Szukanie zawansowane


  Reklama
  Redakcja
  Hosting
  Kanał

© WebCity.pl Team
 
 
  Forum Forum
Kursy Kursy
Porady Porady
Recenzje Recenzje
Newsy Newsy
Katalog stron WWW Katalog
Skrypty PHP Skrypty
Download Oferty i praca
Artykuły:
 Teoria
 Praktyka
 Promocja
 Inne
 

 Webcity.pl |

Pliki XML generowane z bazy danych

Autor: Tony Marston
Wstęp
   Artykuł ten przeznaczony jest dla programistów, którzy zainteresowani są eksportowaniem danych ze swojej bazy do pliku XML tak, by mogły być one łatwo przetwarzane w inny sposób, np. poprzez użycie arkuszy XSL do ich wyświetlenia jako dokumenty hipertekstowe. Metoda tu opisana pozwala całkowicie oddzielić warstwę prezentacji (np. generowanie dokumentów HTML) od warstwy przetwarzania (aplikacja przetwarza dane wedle określonych reguł zaprogramowanych w języku np. PHP), dzięki czemu modyfikacja jednej nie powoduje konieczności dokonywania zmian w drugiej.

   W poniższych przykładach kod został tak napisany, że nie ma w nim zapisanych "na twardo" żadnych nazw tabel, pól itd. Dane pobierane są z bazy jako tablica asocjacyjna (pary "nazwa-wartość"). Każdy jej element jest zamieniany i zapisywany w pliku XML, a jej zawartość pobierana przy pomocy zapytania SQL "SELECT".

   Na początku zaprezentuję sposób zapisania informacji z pojedynczej tabeli, a następnie z dwóch różnych powiązanych wzajemnymi relacjami. Na końcu znajdzie się krótki opis wprowadzenia dodatkowych atrybutów do utworzonych znaczników w celu uzupełnienia/skomentowania danych.

Wymagania
   Wszystkie przykłady wymagają zainstalowanego w PHP rozszerzenia "DomXML". Zalecana jest także znajomość budowy plików XML.

Pobieranie danych z pojedynczej tabeli
   Poniższy kod ma za zadanie pobrać wszystkie rekordy z $dbresult (każde pole w rekordzie jest jedną parą "nazwa-wartość") i zapisać je jako znaczniki XML'a. W zależności od woli programisty/użytkownika mogą one być potem prosto zachowane w postaci pliku, lub przetworzone na kod HTML za pomocą rozszerzenia PHP "Sablotron XSLT processor". Pierwsza część kodu po prostu łączy się z bazą i przygotowuje odpowiednie zapytanie:

<?php
   if (!$dbconnect = mysql_connect('localhost', 'user', 'pass')) {
      echo "Nie mogę się połączyć z hostem 'localhost'.";
      exit;
   } // if
   if (!mysql_select_db('test')) {
      echo "Nie mogę się połączyć z bazą 'test'";
      exit;
   } // if

   $table_id = 'jakas_tabela';
   $dbresult = mysql_query("SELECT * FROM $table_id", $dbconnect);

Teraz, mając dane, możemy zacząć je wyświetlać. Na początku utworzymy nowy dokument DOM. Za pomocą poniższej komendy ustalamy, że chodzi nam o wersję 1.0 XML'a, po czym zwracamy referencję do wirtualnego dokumentu.

// Utworz nowy dokument DOM
   $doc = dom_new_doc('1.0');

Pierwszy utworzony element (zwany też węzłem) jest tak zwanym elementem głównym, który musi znaleźć się raz i tylko raz w każdym dokumencie XML'a. W tym przykładzie nazwałem go po prostu "root", lecz możesz oczywiście użyć takiej nazwy, jaka Ci się podoba (np. nazwa wykonywanego skryptu). Pamiętaj, że element ten musisz wprowadzić za pomocą dwóch funkcji:

// Utwórz element (węzeł) ROOT
   $root = $doc->create_element('root');
   $root = $doc->append_child($root);

Jesteśmy teraz gotowi do rozpoczęcia zapisu danych, które mamy w bazie. Zauważ, że zwracam każdy wiersz jako tablicę asocjacyjną, dzięki czemu praktycznie bez problemu odczytam wszystkie pary "nazwa-wartość".

// załaduj wiersz z bazy
   while ($row = mysql_fetch_assoc($dbresult)) {

Pierwszym zadaniem, jakie muszę zrealizować dla każdego rekordu, jest utworzenie nowego węzła tworzonym dokumencie XML, który zapisywany jest bezpośrednio w "roocie". W przykładzie jego nazwa tworzona jest od nazwy tabeli, z której pobieram dane.

// utwórz element/wezel dla kazdego rekordu
      $occ = $doc->create_element($table_id);
      $occ = $root->append_child($occ);

Teraz za pomocą pętli FOREACH pobieram nazwę oraz wartość każdego pola rekordu i zapisuję je do pliku. Jak widać, tablice asocjacyjne potrafią bardzo urpościć życie. Nie muszę zastanawiać się ani nad tym, ile pól mają rekordy, ani w jakiej są one zapisywane kolejności - wszystko załatwia za nas PHP.

// Dodaj węzeł potomny dla każdego z elementów
      foreach ($row as $fieldname => $fieldvalue) {($occ);

Zauważ, że każda kolumna (zwana też polem) zapisywana jest jako element potomny węzła oznaczającego rekord, tutaj identyfikowanego za pomocą zmiennej $occ.

         $child = $doc->create_element($fieldname);
         $child = $occ->append_child($child);

Muszę zapisać do utworzonego węzła wartość aktualnie przetwarzanego pola.

         $value = $doc->create_text_node($fieldvalue);
         $value = $child->append_child($value);

Pętle są wykonywane dopóty, dopóki nie zostaną zapisane wszystkie rekordy i kolumny.

      } // foreach
   } // while

Ostatni fragment kodu zwraca gotowy dokument XML

// pobierz gotowy dokument XML
   $xml_string = $doc->dump_mem(true);

W tym przykładzie po prostu wyświetlam całość na ekranie przeglądarki, lecz w zależności od potrzeb można tutaj zaprogramować parę dodatkowych metod przetwarzania, np. przepuszczenie wyniku przez procesor XSLT, który dzięki arkuszowi XSL wygeneruje nam kod HTML z osadzonymi w nim danymi z bazy.

   echo $xml_string;
?>

Zawartość utworzonego dokumentu XML będzie prezentowała się mniej więcej następująco, rozpoczynając od deklaracji XML oraz elementu ROOT.

<?xml version="1.0"?>
<root>

Każdy z rekordów w bazie będzie posiadał swój element w dokumencie, będący potomkiem elementu ROOT. Będzie on zawierał w sobie znaczniki reprezentujące pojedyncze kolumny. Zauważ, iż każdy taki znacznik posiada węzeł tekstowy, w którym przechowuje dane, podczas gdy znacznik rekordu takiego węzła nie posiada. Po ostatniej kolumnie dostrzec możesz tag zamykający, po którym jest on znów otwierany dla kolejnego rekordu pobranego z bazy.

   <jakas_tabela>
      <kolumna1>wartosc1</kolumna1>
      <kolumna2>wartosc2</kolumna2>
      ........................
      <kolumnaX>wartosc3</kolumnaX>
   </jakas_tabela>
   <jakas_tabela>
      ........................
   </jakas_tabela>

W ostatniej linii zamykany jest znacznik ROOT.

</root>

Wszystkie znaczniki użyte w tym dokumencie posiadają zarówno formę otwierającą, jak i zamykającą: <element>...</element>. Znacznik taki jest pojedynczym węzłem pliku XML. Wszystko w nim zawarte zwane jest węzłami potomnymi tego właśnie elementu. Mogą one przyjąć postać zwykłego węzła tekstowego (<znacznik>blebleble</znacznik>), lub też być elementami podrzędnymi.

   Czasami możesz dostrzec w dokumentach XML znacznik w formie <znacznik />. XML dopuszcza możliwość otwarcia i zamknięcia znacznika między jedną tylko klamrą ukośną. Dla nas oznacza to, iż jest on pusty tzn. nie zawiera żadnych węzłów potomnych.

Dwie tabele połączone wzajemnymi relacjami
W następnym przykładzie generowany dokument XML będzie zawierał dane z dwóch tabel połączonych relacją One-to-many (czyli kilka rekordów podrzędnych z jednej tabeli uzupełnia dane w jednym wybranym z drugiej). Dane pobierane są z wyników dwóch zapytań: $resouter dla tabeli nadrzędnej i $resinner dla tabeli podrzędnej. Tym razem, by się nie powtarzać, skomentuję tylko ten kod, gdzie nastąpiły zmiany.

<?php
   if (!$dbconnect = mysql_connect('localhost', 'user', 'pass')) {
      echo "Nie można połączyć się z hostem 'localhost'.";
      exit;
   } // if
   if (!mysql_select_db('test')) {
      echo "Nie można połączyć się z bazą danych 'test'";
      exit;
   } // if

Tutaj widać dwa oddzielne zapytania dla każdej z tabel:

   $outer_table = 'tabela_nadrzedna';
   $resouter = mysql_query("SELECT * FROM $outer_table WHERE column='wartosc'", $dbconnect);

   $inner_table = 'tabela_podrzedna';
   $resinner = mysql_query("SELECT * FROM $inner_table WHERE column='wartosc'", $dbconnect);

Następnie tworzymy nowy dokument DOM i dodajemy element ROOT:

// utwórz dokument XML
   $doc = domxml_new_doc('1.0');

// dodaj element ROOT
   $root = $doc->create_element('root');
   $root = $doc->append_child($root);

Pobieramy JEDEN rekord z tabeli nadrzędnej i tworzymy dla niego węzeł w dokumencie.

// dodaj wezel rekordu z tabeli nadrzednej
   $outer = $doc->create_element($outer_table);
   $outer = $root->append_child($outer);

// pobierz jeden rekord z tabeli
   $row = mysql_fetch_assoc($resouter);

Nie możemy zapomnieć o wyeksportowaniu kolumn do pliku:

// utwórz węzeł potomny dla każdej kolumny z rekordu
   foreach ($row as $fieldname => $fieldvalue) {
      $child = $doc->create_element($fieldname);
      $child = $outer->append_child($child);
      $value = $doc->create_text_node($fieldvalue);
      $value = $child->append_child($value);
   } // foreach

Tutaj dodajemy węzły dla każdego rekordu pobranego z tabeli podrzędnej. Zauważ, że każdy z nich jest potomkiem elementu $outer, a nie $root. Wszystkie kolumny węzła $inner będą jego potomkami.

// przetworz dane wezlow potomnych
   while ($row = mysql_fetch_assoc($resinner)) {
   // utworz wezel
   $inner = $doc->create_element($inner_table);
   $inner = $outer->append_child($inner);
   // utworz wezly dla kolumn
   foreach ($row as $fieldname => $fieldvalue) {
      $child = $doc->create_element($fieldname);
      $child = $inner->append_child($child);
      $value = $doc->create_text_node($fieldvalue);
      $value = $child->append_child($value);
   } // foreach
} // while

// pobierz tresc dokumentu XML
$xml_string = $doc->dump_mem(true);
echo $xml_string;
?>

Kod ten wyprodukuje dokument XML o takiej strukturze:

<?xml version="1.0"?>
<root>
   <tabela_nadrzedna>
      <kolumna1>wartosc1</kolumna1>
      <kolumna2>wartosc2</kolumna2>
      <kolumna3>wartosc3</kolumna3>
      ...............
      <tabela_podrzedna>
         <kolumna1>wartosc1</kolumna1>
         <kolumna2>wartosc2</kolumna2>
         <kolumna3>wartosc3</kolumna3>
         ...............
      </tabela_podrzedna>
      <tabela_nadrzedna>
         ...............
      </tabela_podrzedna>
      ...............
   </tabela_podrzedna>
</root>

Jak widać, <tabela_podrzedna> zagnieżdżona jest w <tabela_nadrzedna>, a ta w <root>. <tabela_nadrzedna> posiada zarówno znaczniki reprezentujące kolumny tegoż, jak i te identyfikujące poszczególne rekordy z tabeli podrzędnej.

Dodawanie atrybutów
   Możliwe, że czasami zechcesz wstawić do znaczników dodatkowe informacje. Może to być zrealizowane za pomocą atrybutów. Atrybut posiada nazwę i wartość, a każdy znacznik może posiadać dowolną ich ilość. W DomXML dodajemy je za pomocą metody '->set_attribute' wstawionej pomiędzy '->append_child', oraz '->create_text_node', np:

$child = $doc->create_element($fieldname);
$child = $outer->append_child($child);
// dodaj atrybuty
$child->set_attribute('attr1', 'attrval1');
$child->set_attribute('attr2', 'attrval2');
// kontynuuj dodawanie danych
$value = $doc->create_text_node($fieldvalue);
$value = $child->append_child($value);

Wygeneruje to mniej więcej taki dokument XML:

<?xml version="1.0"?>
<root>
   <tabela>
      <kolumna1 attr1="jakas_wartosc" attr2="jakas_wartosc">wartosc1</kolumna1>
      <kolumna2 attr1="jakas_wartosc" attr2="jakas_wartosc">wartosc2</kolumna2>
      <kolumna3 attr1="jakas_wartosc" attr2="jakas_wartosc">wartosc3</kolumna3>
   </tabela>
</root>

Atrybuty możesz dodać zarówno do elementów reprezentujących rekordy, jak i kolumny (pola).

   W moich własnych aplikacjach używam atrybutów do określenia, jak dużo danych znajduje się w każdej kolumnie. Dzięki temu nie muszę tego zakodowywać "na twardo" w arkuszach XSL. Dla danych wielowierszowych tworzę atrybuty 'rows' (wiersze), oraz 'cols' (kolumny).

   Używam także atrybutów do dołączania różnych komunikatów błędów. Wszystkie one są zapisywane w tablicy $errors, gdzie klucz jest nazwą pliku, a wartość odpowiednim komunikatem. Jest on wstawiany jako atrybut do pola, które go wygenerowało, np.

if (isset($errors[$fieldname])) {
   $child->set_attribute("error", $errors[$fieldname]);
} // if


Zakończenie
   Dzięki użyciu tej metody byłem w stanie zaprojektować uniwersalny mechanizm tworzenia plików XML na podstawie danych z relacyjnych systemów baz. Wszystko, czego potrzebowałem, to określić nazwy(ę) tabel(i), oraz ustalić kryteria wyboru odpowiednich informacji. Później za pomocą arkusza XSL bez problemu wygenerowałem statyczne dokumenty HTML.

O autorze
Tony Marston jest weteranem w dziedzinie projektowania oprogramowania w językach drugiej, trzeciej i czwartej generacji; głównie jeśli chodzi o aplikacje klient/serwer. Niedawno zainteresował się technologią PHP/MySQL jako doskonałą platformą do ich tworzenia. Obecnie pracuje nad sieciowym systemem korzystającym z PHP/MySQL, gdzie cały kod HTML jest utworzony za pomocą XML/XSL, oraz własnoręcznie napisanych mechanizmów.

Możesz się z nim skontaktować poprzez jego stronę domową http://www.tonymartson.net

Przetłumaczył ZyxwvU (zyxwvu@me2.pl)
Publikowane i tłumaczone za zgodą autora (wyłączność dla Webcity)
Tekst oryginalny: http://www.zend.com/zend/tut/tutorial-DOM-XML.php

Powrót