Laboratorium - XML + XSL

Poniższe ćwiczenia dotyczą technologii XML: DTD, XML Schema oraz XSLT. Do ich wykonania potrzebny jest edytor plików tekstowych (vim, kate, notepad) oraz przeglądarka internetowa (Firefox). Przeglądarka Chrome wymaga instalacji dodatkowych wtyczek do poprawnej wizualizacji niektórych zagadnień. Jako literaturę polecam:

Uwaga! Rezultat każdego zadania powinien być sprawdzony poprzez serwis umożliwiający odpowiednią walidację DTD/XML Schema.

  1. Utwórz nowy dokument XML wraz z definicją DTD, a następnie otwórz go w przeglądarce. Jak zinterpretowała go przeglądarka? Dokonaj walidacji poprzez serwis http://validator.w3.org/#validate_by_input.

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE note [
    <!ELEMENT note (to,from,heading,body)>
    <!ELEMENT to (#PCDATA)>
    <!ELEMENT from (#PCDATA)>
    <!ELEMENT heading (#PCDATA)>
    <!ELEMENT body (#PCDATA)>
    ]>
    <note>
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
    <body>Send me the data I requested</body>
    </note>
    
  2. Definicja DTD może być zapisana także w zewnętrznym pliku (np. note.dtd)

    <!ELEMENT note (to,from,heading,body)>
    <!ELEMENT to (#PCDATA)>
    <!ELEMENT from (#PCDATA)>
    <!ELEMENT heading (#PCDATA)>
    <!ELEMENT body (#PCDATA)>
    

    Wówczas dokument XML powinien zawierać referencję do zewnętrznego pliku

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE note SYSTEM "note.dtd">
    <note>
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
    <body>Send me the data I requested</body>
    </note>
    
  3. Do dotychczasowej definicji dokumentu dodaj informację o pustym elemencie <!ELEMENT urgent EMPTY> i dołącz go do sekwencji elementu note oznaczając krotność wystąpienia na dokładnie zero lub jedno znakiem ?.

  4. Dodaj możliwość zdefiniowania dodatkowych odbiorców wiadomości. W tym celu dodaj element o nazwie cc typu PCDATA oraz umieść go na liście sekwencji z odpowiednią krotnością zero lub wiele.

  5. Aby umożliwić formatowanie wiadomości znacznikami <i> oraz <b> należy dodać odpowiednie definicje elementów oraz zmodyfikować element body: <!ELEMENT body (#PCDATA|b|i)*>. Przetestuj możliwość formatowania wiadomości. Czy tak zdefiniowane znaczniki można w sobie zagnieżdżać?

  6. Do definicji elementu note dodaj atrybut o nazwie read o domyślnej wartości false. Będzie on oznaczał, czy wiadomość została już przeczytana: <!ATTLIST note read (true|false) false>. Umieść w dokumencie XML informację, że wiadomość została już przeczytana: <note read="true">. Czy można wstawić inną wartość atrybutu niż true/false?

  7. Do elementu note dodaj obowiązkowy atrybut id: <!ATTLIST note id ID #REQUIRED>.

  8. Zmodyfikuj definicję elementu głównego (root element), umożliwiając wstawienie kilku wiadomości do jednego dokumentu XML. Dodamy element notes, który będzie zawierał conajmniej jeden element note. Zmodyfikuj odpowiednio dokument XML.

    <!DOCTYPE notes [
    <!ELEMENT notes (note+)>
    ..
    
  9. Korzystając ze zmodyfikowanej definicji z poprzedniego zadania wykonaj (każdorazowo sprawdzając poprawność dokumentu):
    1. Wstaw kolejną wiadomość do dokumentu (element note)
    2. Sprawdź czy atrybut id może zawierać powtarzające się wartości.
    3. Do definicji dodaj opcjonalny atrybut <!ATTLIST note re IDREF #IMPLIED>, który będzie oznaczał identyfikator wiadomości, na którą odpowiadamy.
    4. Przetestuj działanie atrybutu re wstawiając identyfikator istniejącej/nieistniejącej wiadomości. Czy walidacja kończy się błędem?
  10. Zdefiniuj encję, a następnie użyj jej np. w ciele wiadomości. Przykładowa encja to <!ENTITY me "Jan Kowalski">, natomiast treść wiadomości może wyglądać następująco: <body>Send me the data I requested. All best, &me;</body>.

  11. Utwórz dokument notes-schema.xml zawierający definicję XML Schema. Definicja reprezentuje wybrane elementy z dotychczasowych ćwiczeń.

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema targetNamespace="www.cs.put.poznan.pl"
            elementFormDefault="qualified" attributeFormDefault="unqualified"
            xmlns="www.cs.put.poznan.pl" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="notes">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="note" maxOccurs="unbounded">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="heading" type="xs:string"/>
                  <xs:element name="body" type="xs:string"/>
                </xs:sequence>
                <xs:attribute name="id" type="xs:integer" use="required"/>
                <xs:attribute name="read" type="xs:boolean" use="optional"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    
  12. Utwórz dokument XML zawierający wiadomości, ale zgodnie z podanym powyżej schematem XML. Dokonaj walidacji dokumentu xml oraz schematu w serwisie http://tools.decisionsoft.com/schemaValidate/.

    <?xml version="1.0" encoding="utf-8"?>
    <notes xmlns="www.cs.put.poznan.pl" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
                     xs:schemaLocation="www.cs.put.poznan.pl notes-schema.xml">
    ...
    </notes>
    
  13. Do schematu XML dodaj opcjonalny element <xs:element name="date" type="xs:dateTime" minOccurs="0"/> reprezentujący datę wysłania wiadomości. Dodaj odpowiedni wpis w dokumencie XML, zgodnie z formatem YYYY-MM-DDThh:mm:ss. Sprawdź jak działa ograniczenie formatu daty.

  14. Wstaw w schemaci XML element odpowiadający adresatowi wiadomości. Tym razem posłużymy się wyrażeniem regularnym, by umożliwić wprowadzanie jedynie poprawnych adresów email.

    <xs:element name="to">
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:pattern value="[a-zA-Z\.]+@([a-zA-Z0-9]+\.)+[a-zA-Z]{2,6}"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:element>
    
  15. Dodaj informację o priorytecie wiadomości. Wstaw odpowiednią definicję elementu priority, który może przyjąć jedną z trzech zdefiniowanych wartości. Czy podanie domyślnej wartości sprawia, że element jest nieobowiązkowy?

    <xs:element name="priority" default="normal">
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:enumeration value="high"/>
          <xs:enumeration value="normal"/>
          <xs:enumeration value="low"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:element>
    
  16. Stwórz arkusz transformujący dokument XML do postaci HTML w pliku transform.xsl.

    <?xml version="1.0" encoding="windows-1250"?>
    <xsl:stylesheet version="1.0"
         xmlns:f="www.cs.put.poznan.pl"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:fo="http://www.w3.org/1999/XSL/Format">
    
    <xsl:template match="f:notes">
      <html>
        <head>
          <title>Lista wiadomości</title>
        </head>
        <body>
            <h1>Notes</h1>
            <xsl:apply-templates/>
        </body>
      </html>
    </xsl:template>
    </xsl:stylesheet>
    
  17. W pliku XML z danymi wstaw w drugiej linii deklarację arkusza stylistycznego <?xml-stylesheet type="text/xsl" href="trans.xsl"?>. Przetestuj, jak dokument xml jest teraz prezentowany w przeglądarce.

  18. Do arkusza stylistycznego dodaj regułę transformującą (wzorzec) elementy note. Samodzielnie dopisz wyświetlanie nadawcy, odbiorcy oraz daty wysłania notatki.

    <xsl:template match="f:note">
    <h2><xsl:value-of select="@id"/>. <xsl:value-of select="f:heading"/></h2>
    <p>
            <xsl:value-of select="f:body"/>
    </p>
    </xsl:template>
    
  19. Dla wiadomości oznaczonych jako nieprzeczytane, ustaw kolor nagłówka (<h2>) lub paragrafu (<p>) na czerwony, korzystając z poniższego wyrażenia warunkowego.

    <xsl:if test="@read='false'">
            <xsl:attribute name="style">color: red</xsl:attribute>
    </xsl:if>
    
  20. Dodaj listę nagłówków wiadomości wyświetlaną na początku dokumentu. W tym celu posłużymy się wzorcem dopasowanym do elementu note. Poniżej znajduje się zmodyfikowany element <body> oraz nowy wzorzec. Zauważ, że dla elementu note będą teraz dostępne dwa wzorce. Który zostanie zastosowany?

    <body>
       <ul>
           <xsl:apply-templates/>
       </ul>
       <h1>Notes</h1>
       <p style="color: red">asdfaewf</p>
       <xsl:apply-templates/>
    </body>
    
    <xsl:template match="f:note">
            <li>
                    <span>
                    <xsl:value-of select="f:heading"/>
                    <xsl:if test="@read='false'">
                            <xsl:attribute name="style">color: red</xsl:attribute>
                    </xsl:if>
                    </span>
            </li>
    </xsl:template>
    
  21. Popraw powyższy przykład dodając tryb działania (kontekst) o nazwie np. toc dla nowego wzorca: <xsl:apply-templates mode="toc"/> oraz <xsl:template match="f:note" mode="toc">. Dzięki temu oba wzorce są rozróżnialne i możemy zastosować je w zależności od kontekstu - w spisie treści (toc, ang. table of contents), bądź w liscie wiadomości.