XML_Programmierung_Teil_2

ehemalige Veranstaltungen ia3.netz + ia3.data sowie ia4.Netz im Studiengang Interaktive Medien

(c) 2020 Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever

XML Programmierung - Teil 2 (DOM)

3.) DOM (Document Object Model)

Generelles

Hier in diesem Skript wird nur auf die wichtigsten Eigenschaften von DOM Wert gelegt, genauere Angaben sowie diverse Einschränkungen oder Beschränkungen sind auf den DOM-Seiten des W3C bzw. in den Spezifikationen zu den einzelnen DOM Level 1, 2 und 3, beschrieben. Die folgenden Abschnitte stammen sowohl aus den Spezifikationen selbst (insbesondere die Bildquellen) als auch aus dem XML-Skript von Mario Jeckle

Document Object Model

Die W3C-Spezifikation des Document Object Models (abgekürzt als: DOM) definiert eine Programmiersprachen-unabhängig formulierte Menge abstrakter Schnittstellen zum lesenden und schreibenden Zugriff auf gültige HTML und wohlgeformte XML-Dokumente sowie eine Reihe weiterer Formate.

  1. Schon seit 2000 ist das sog. DOM Level 1 im Status einer W3C-Recommendation verabschiedet.

  2. DOM Level 2 erweitert die in Level 1 eingeführten Schnittstellen hinsichtlich der Erfordernisse von XML-Dokumenten mit Namensräume und bietet einige neue Operationen, die seitens der Anwendergemeinde gefordert wurden. Die bisherigen Operationen existieren aus Kompatibilitätsgründen weiter, die Namespace-berücksichtigenden Pendants sind identisch benannt, jedoch um ein angehängtes NS erweitert.

  3. DOM Level 3 erweitert die in Level 2 aufgeführten Schnittstellen u.a. um die Erfordernisse von XML-Dokumenten mit Zeichenkodierungen.

  4. DOM4 konsolidiert DOM Level 3 Core und einige andere Module, wurde an die derzeit notwendigen JavaScript-Bedürfnisse und bereits implementierten DOM-Bibliotheken angepasst und soweit wie möglich vereinfacht.

DOM als API

DOM versteht sich als Application Programming Interface (API) für beliebige XML-Dokumente und ist für beliebige Programmiersprachen auf der Basis der OMG (Object Management Group) IDL (Interface Definition Language) verwendbar.

Hierzu versammelt es auf Basis einer generischen Speicherrepräsentation für XML eine Menge von Operationen zur Extraktion verschiedenster Informationen aus dem Dokument, sowie zur Modifikation der speicherresidenten Strukturen und späteren (Wieder-)Ausgabe in ein XML-Dokument.

Eine wichtige Eigenschaft der DOM Struktur ist der strukturelle Isomorphismus: falls irgendwelche zwei Document Object Model Implementierungen benutzt werden um das gleiche Dokument zu repräsentieren, müssen beide auch das gleiche Strukturmodell bezgl. des XML Information Sets erzeugen.

(s. in DOM Level 3 - Core den Abschnitt What is the Document Object Model bzw. in DOM4 das Kapitel 4.1 Introduction to "The DOM")

Objektmodell

Als Objektmodell identifiziert das DOM

  • die Schnittstellen und Objekte, die zur Repräsentation und Manipulation eines HTML oder XML Dokuments benutzt werden
  • die Semantik dieser Schnittstellen und Objekte - einschliesslich deren Verhalten und Eigenschaften
  • die Beziehungen und Zusammenhänge unter diesen Schnittstellen und Objekten

Jedes Objekt (sei es Element oder Attribut oder einfach nur Text) wird dabei durch einen Knoten des entsprechenden XML-Baumes repräsentiert.

Dabei hat jeder Knoten des Baums einen

  • Knotentyp (nodeType)
  • Elternknoten (parentNode)

und er kann folgende Objekte besitzen:

  • eine Liste von Kindknoten (childNodes)
  • ersten Kindknoten (firstChild)
  • letzten Kindknoten (lastChild)
  • Vorgänger (previousSibling)
  • Nachfolger (nextSibling)

Die wichtigsten Knotentypen sind Elementknoten, Attributknoten, Text- bzw. CharacterData-knoten und Dokumentknoten.

Das DOM

  • ist keine Menge von Datenstrukturen, sondern ein Objektmodell, welches Schnittstellen spezifiziert
  • definiert nicht, welche Informationen in einem Dokument relevant sind oder wie die Informationen in einem Dokument strukturiert sind. Für XML ist dies durch das XML Information Set spezifiziert. Das DOM ist eine API zu diesem XML Information Set.
  • ist auch nicht mit dem Component Object Model (COM) vergleichbar. COM ist wie CORBA ein sprachunabhängiger Weg um Schnittstellen und Objekte zu beschreiben.

Chance im Team

Diskutieren sie kurz mit ihrem Nachbarn/Teampartner den Unterschied zwischen XML und DOM !

Was kann XML und was kann DOM ?

Zu was kann ich DOM brauchen ?

DOM Beispiel 1 aus der älteren DOM Level 3 Recommendation

Tabelle in einem HTML-Dokument

 <TABLE>
    <TBODY> 
      <TR> 
        <TD>Shady Grove</TD>
        <TD>Aeolian</TD> 
      </TR> 
      <TR>
        <TD>Over the River, Charlie</TD>        
        <TD>Dorian</TD> 
      </TR> 
    </TBODY>
  </TABLE>

Diese HTML-Tabelle wird durch das Document Object Model folgendermaßen repräsentiert:

DOM Level 3 - Repräsentation HTML Tabelle (Quelle: W3C)

Diese Repräsentation steht auch als SVG Bild zur Verfügung

Jedes Objekt dieses Baums kann nun - jeweils zurückverfolgbar zum Wurzel-Element - über einen bestimmten Weg und damit über eine bestimmte Notation erreicht werden.

Eine entsprechende JavaScript Umsetzung könnte dann folgendermaßen lauten:

// Erreichbarkeit des Elements tbody (myTbodyElement) über das Wurzelelement table (myTableElement)
var myTbodyElement = myTableElement.firstChild;

// Erreichbarkeit des zweiten Elements tr ausgehend von dem Element tbody (myTbodyElement)
// Beachte: die Liste der Kindelemente beginnt bei 0 (und nicht bei 1)
var mySecondTrElement = myTbodyElement.childNodes[1];

// Lösche das erste Element td von diesem zweiten Element tr (mySecondTrElement)
mySecondTrElement.removeChild(mySecondTrElement.firstChild);

// Ändere den Inhalt des Textknotens von dem verbleibendem Element td zu "Peter"
mySecondTrElement.firstChild.firstChild.data = "Peter"

DOM Beispiel 2 aus der neueren DOM4 Recommendation

HTML-Dokument

<!DOCTYPE html>
<html class=e>
 <head><title>Aliens?</title></head>
 <body>Why yes.</body>
</html>

siehe auch den Live Dom Viewer

In [1]:
%%html
<ul class="domTree">
 <li>
  <a href="#concept-document" title="concept-document">Document</a>
  <ul>
   <li class="t10"><a href="#concept-doctype" title="concept-doctype">Doctype</a>: <code>html</code></li>
   <li class="t1"><a href="#concept-element" title="concept-element">Element</a>: <code>html</code> <span class="t2"><code class="attribute name">class</code>="<code class="attribute value">e</code>"</span>
    <ul>
     <li class="t1">
      <a href="#concept-element" title="concept-element">Element</a>: <code>head</code>
      <ul>
       <li class="t1">
        <a href="#concept-element" title="concept-element">Element</a>: <code>title</code>
        <ul>
         <li class="t3"><code><a href="#text">Text</a></code>: <span>Aliens?</span></li>
        </ul>
       </li>
      </ul>
     </li>
     <li class="t3"><code><a href="#text">Text</a></code>: <span>⏎␣</span></li>
     <li class="t1">
      <a href="#concept-element" title="concept-element">Element</a>: <code>body</code>
      <ul>
       <li class="t3"><code><a href="#text">Text</a></code>: <span>Why yes.⏎</span></li>
      </ul>
     </li>
    </ul>
   </li>
  </ul>
 </li>
</ul>

Chance im Team

Halten sie sich diese kleinen Beispiele vor Augen und diskutieren sie kurz mit ihrem Nachbarn, was ein wesentlicher Unterschied zwischen SAX und DOM sein könnte.

Hinweis:

Denken sie daran wie SAX ein XML-Dokument verarbeitet und wie DOM ein XML-Dokument verarbeiten muss.

Das DOM Struktur Modell

Das DOM präsentiert Dokumente als Hierarchie von Knotenobjekten, die gleichzeitig andere, spezielle Schnittstellen implementiert. Einige Knotentypen haben Kinder diverser Typen und andere sind Blattknoten, die nichts anderes mehr unter sich haben können.

DOM-Knotentypen für XML / HTML

Für XML / HTML stehen folgende Knotentypen mit ihren entsprechenden Kindern zur Verfügung (s. Kapitel 4.2 Node Tree):

  • Document -- Element (maximal eines), ProcessingInstruction, Comment, DocumentType (maximal eines)
  • DocumentFragment -- Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
  • DocumentType -- keine Kinder
  • Element -- Element, Text, Comment, ProcessingInstruction, CDATASection, EntityReference
  • Text -- keine Kinder
  • ProcessingInstruction -- keine Kinder
  • Comment -- keine Kinder

Für DOM Level 3 sind noch die folgenden Knotentypen spezifiziert: (s. The DOM Structure Model)

  • EntityReference -- Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
  • Attr -- Text, EntityReference
  • CDATASection -- keine Kinder
  • Entity -- Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
  • Notation -- keine Kinder

NodeList und NamedNodeMap

Das DOM spezifziert zudem eine - in DOM4 als old-style collection definierte - Schnittstelle NodeList um geordnete Listen von Knoten, z.B. die Kinder eines Knotens oder die Elemente, die durch einen Aufruf der Methode Element.getElementsByTagNameNS(namespaceURI, localName) zurückgegeben wird, behandeln zu können. Eine weitere Schnittstelle namens NamedNodeMap wird noch aus der DOM Level 3 Definition weiterverwendet, um eine ungeordnete Menge von Knoten, die durch einen Namen referenziert werden, z.B. die Attribute eines Elements, bearbeiten zu können.

Beachte: NodeList und NamedNodeMap Objekte im DOM sind live-Objekte; d.h. Änderungen in der darunterliegenden Dokumentstruktur wirken sich in allen relevanten NodeList und NamedNodeMap Objekten aus.

CharacterData

Die Schnittstellen Text, Comment, und CDATASection erben alle von der Schnittstelle CharacterData.

DOM Interface

Beispiele aus der DOM4 Empfehlung des W3C

Chance im Team

Diskutieren sie mit ihrem Teampartner die Vorteile der W3C Spezifikations-Seite in Bezug auf die Definition der API mittels der Interface Definition Language.

Hinweis:

Das W3C hat die XML Spezifikation bezüglich der Definition mittels der Extended Backus Naur Form ähnlich aufgebaut.

DOM in Python

xml.dom als Standard DOM API für Python

xml.dom.minidom als DOM Parser für Python

DOM Programmierbeispiele

Einfacher XML DOM Parser

mit der xml.dom.minidom Bibliothek

In [2]:
#! /usr/bin/python
# -*- coding: utf-8 -*-
from xml.dom.minidom import parse, parseString
from xml.dom import DOMException, Node
from urllib.request import urlopen

def getChildElements(node):
    elements = []
    for n in node.childNodes:
        if n.nodeType == Node.ELEMENT_NODE:
            elements.append(n)
    return elements

def getElementText(node):
    return node.childNodes[0].data

class XMLasDOM():
    
    def __init__(self,xmldocument=None,filename=None):
        if xmldocument:
            if xmldocument.startswith('http'):
                f = urlopen(xmldocument)
                xmldocument = f.read()
            self.document = parseString(xmldocument)
        elif filename:
            self.document = parse(filename)
        else:
            raise ValueError("kein Argument übergeben")
        self.root = self.document.documentElement

kontakteDokument = XMLasDOM(filename='kontakte.xml')
print("alle E-Mail Adressen:")
print('-'*60)
root = kontakteDokument.root
for kontakt in getChildElements(root):
    for kontaktelement in getChildElements(kontakt):
        if kontaktelement.tagName == 'Kontaktdaten':
            for kontaktdatenelement in getChildElements(kontaktelement):
                if kontaktdatenelement.tagName == 'EMail':
                    print(getElementText(kontaktdatenelement))
print('-'*60)
print("gesamtes Dokument:")
print('-'*60)
print(root.toxml())
alle E-Mail Adressen:
------------------------------------------------------------
Lord.Mustermann@hs-augsburg.de
Lord.Mustermann@web.de
Moritz.Lehmann@hs-augsburg.de
m.lehmann@web.de
------------------------------------------------------------
gesamtes Dokument:
------------------------------------------------------------
<Kontakte>
  <Kontakt Markierung="unwichtig" Typ="kein Freund">
    <Person Geburtstag="1.1.1970" Geschlecht="männlich">
      <Name>Mustermann</Name>
      <Vorname>Max</Vorname>
      <Geburtsname/>
      <Titel>Lord</Titel>
      <Namenszusatz/>
    </Person>
    <Kontaktdaten Typ="geschäftlich">
      <Adresse>
        <Strasse>Unter der Brücke</Strasse>
        <Hausnummer>10</Hausnummer>
        <PLZ>86150</PLZ>
        <Ort>Augsburg</Ort>
        <Land>Bayern</Land>
        <Zusatzinfo>Schwaben</Zusatzinfo>
        <Postfach/>
      </Adresse>
      <Telefonnummer>123456789</Telefonnummer>
      <Telefonnummer Typ="mobil">0190-987654321</Telefonnummer>
      <EMail>Lord.Mustermann@hs-augsburg.de</EMail>
    </Kontaktdaten>
    <Kontaktdaten Typ="privat">
      <Adresse>
        <Strasse>Unter der Lechbrücke</Strasse>
        <Hausnummer>2</Hausnummer>
        <Plz>86150</Plz>
        <Ort>Augsburg</Ort>
        <Land>Bayern</Land>
        <Zusatzinfo>Schwaben</Zusatzinfo>
        <Postfach/>
      </Adresse>
      <Telefonnummer>567890</Telefonnummer>
      <Telefonnummer Typ="mobil">0160-23456790</Telefonnummer>
      <EMail>Lord.Mustermann@web.de</EMail>
      <Notizzettel>stinkt ein bißchen</Notizzettel>
    </Kontaktdaten>
    <Notizzettel/>
  </Kontakt>
  <Kontakt Markierung="wichtig" Typ="Freund">
    <Person Geburtstag="1.1.1990" Geschlecht="männlich">
      <Name>Lehmann</Name>
      <Vorname>Moritz</Vorname>
      <Geburtsname/>
      <Titel> </Titel>
      <Namenszusatz/>
    </Person>
    <Kontaktdaten Typ="geschäftlich">
      <Adresse>
        <Strasse>Friedberger Str.</Strasse>
        <Hausnummer>2</Hausnummer>
        <Plz>86161</Plz>
        <Ort>Augsburg</Ort>
        <Land>Bayern</Land>
        <Zusatzinfo>Schwaben</Zusatzinfo>
        <Postfach/>
      </Adresse>
      <Telefonnummer>5586-7900</Telefonnummer>
      <Telefonnummer Typ="mobil">0170-987654321</Telefonnummer>
      <EMail>Moritz.Lehmann@hs-augsburg.de</EMail>
    </Kontaktdaten>
    <Kontaktdaten Typ="privat">
      <Adresse>
        <Strasse>Badstrasse</Strasse>
        <Hausnummer>20</Hausnummer>
        <Plz>86150</Plz>
        <Ort>Augsburg</Ort>
        <Land>Bayern</Land>
        <Zusatzinfo>Schwaben</Zusatzinfo>
        <Postfach/>
      </Adresse>
      <Telefonnummer>8976890</Telefonnummer>
      <Telefonnummer Typ="mobil">0161-12342345</Telefonnummer>
      <EMail>m.lehmann@web.de</EMail>
      <Überschrift>ÄÖüß</Überschrift>
    </Kontaktdaten>
    <Notizzettel/>
  </Kontakt>
</Kontakte>

Aktives Plenum 1

Erweitern sie das obige DOM Programm

  1. Erstellen Sie eine zusätzliche Methode search(nachname,vorname,typ), die
  2. alle Kontakte nach einem Nachnamen und einem Vornamen durchsucht,
  3. alle Kontaktdaten dieses Kontakts mit einem bestimmten Typ auswählt,
  4. alle mobilen Telefonnummern dieses Kontakts sowie
  5. die Adresse des Kontakts in der Form Strasse Hausnummer, Plz Ort zurückgibt
  6. Gehen sie dabei davon aus, dass in dem XML Dokument die Kombination Vorname + Nachname eindeutig ist

SVG (Scalable Vector Graphics)

Innerhalb des W3C Konsortiuums gibt es einen Bereich der sich mit Graphics beschäftigt, darunter fällt sowohl Portable Network Graphics (PNG) als auch Scalable Vector Graphics (SVG).

Unter dem Link SVG Recommendation ist der derzeitige Standard nachlesbar. Ein bereits älteres, aber noch immer sehr ausführliches SVG Tutorial findet sich ebenfalls auf den W3C-Seiten. Das O'Reilly Buch SVG Essentials wurde auch in die O'Reilly Commons Bücher aufgenommen. Auch auf den Seiten von W3Schools findet sich ein W3Schools SVG Tutorial.

Chance im Team

  • Was ist der Unterschied zwischen PNG und SVG ?
  • Warum sollten wir uns in Interaktive Medien mehr mit SVG denn mit PNG beschäftigen ?

Graphics in Jupyter

Im Jupyter Notebook kann fast jede Art von Graphik mittels des IPython Rich Display System dargestellt werden. Graphiken können dabei sowohl in Markdown Zellen mittels des HTML-Tags <img src="image.png" alt="Titel"> als auch in Code Zellen mittels Magics Befehlen verwendet werden.

SVG in Jupyter

Verwenden wir aus dem O'Reilly Buch SVG Essentials das Beispiel Basic Shapes aus dem ersten Kapitel und verwenden den Magics-Befehl %%SVG in der ersten Zeile:

In [1]:
%%SVG
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
    "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">

<svg width="140" height="170">
<title>Cat</title>
<desc>Stick Figure of a Cat</desc>

<circle cx="70" cy="95" r="50" style="stroke: black; fill: none"/>;

</svg>
Cat Stick Figure of a Cat ;

Nehmen wir jedoch das letzte Beispiel Text aus diesem Kapitel, so ergibt sich eine Fehlermeldung:

In [4]:
%%SVG
<svg width="140" height="170">
<title>Cat</title>
<desc>Stick Figure of a Cat</desc>

<circle cx="70" cy="95" r="50" style="stroke: black; fill: none;"/>
<circle cx="55" cy="80" r="5" stroke="black" fill="#339933"/>
<circle cx="85" cy="80" r="5" stroke="black" fill="#339933"/>
<g id="whiskers">
   <line x1="75" y1="95" x2="135" y2="85" style="stroke: black;"/>
   <line x1="75" y1="95" x2="135" y2="105" style="stroke: black;"/>
</g>
<use xlink:href="#whiskers" transform="scale(-1 1) translate(-140 0)"/>
<!-- ears -->
<polyline points="108 62,  90 10,  70 45,  50, 10,  32, 62"
   style="stroke: black; fill: none;" />
<!-- mouth -->
<polyline points="35 110, 45 120, 95 120, 105, 110"
    style="stroke: black; fill: none;" />

<!-- nose -->
<path d="M 75 90 L 65 90 A 5 10 0  0 0 75 90"
   style="stroke: black; fill: #ffcccc"/>
<text x="60" y="165" style="font-family: sans-serif; font-size: 14pt;
   stroke: none; fill: black;">Cat</text>
</svg>
---------------------------------------------------------------------------
ExpatError                                Traceback (most recent call last)
<ipython-input-4-75f91c1333e8> in <module>()
----> 1 get_ipython().run_cell_magic('SVG', '', '<svg width="140" height="170">\n<title>Cat</title>\n<desc>Stick Figure of a Cat</desc>\n\n<circle cx="70" cy="95" r="50" style="stroke: black; fill: none;"/>\n<circle cx="55" cy="80" r="5" stroke="black" fill="#339933"/>\n<circle cx="85" cy="80" r="5" stroke="black" fill="#339933"/>\n<g id="whiskers">\n   <line x1="75" y1="95" x2="135" y2="85" style="stroke: black;"/>\n   <line x1="75" y1="95" x2="135" y2="105" style="stroke: black;"/>\n</g>\n<use xlink:href="#whiskers" transform="scale(-1 1) translate(-140 0)"/>\n<!-- ears -->\n<polyline points="108 62,  90 10,  70 45,  50, 10,  32, 62"\n   style="stroke: black; fill: none;" />\n<!-- mouth -->\n<polyline points="35 110, 45 120, 95 120, 105, 110"\n    style="stroke: black; fill: none;" />\n\n<!-- nose -->\n<path d="M 75 90 L 65 90 A 5 10 0  0 0 75 90"\n   style="stroke: black; fill: #ffcccc"/>\n<text x="60" y="165" style="font-family: sans-serif; font-size: 14pt;\n   stroke: none; fill: black;">Cat</text>\n</svg>')

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2101             magic_arg_s = self.var_expand(line, stack_depth)
   2102             with self.builtin_trap:
-> 2103                 result = fn(magic_arg_s, cell)
   2104             return result
   2105 

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/magic.py in __call__(self, *args, **kwargs)
    680                 args_list[0] = self.magic_params + " " + args[0]
    681                 args = tuple(args_list)
--> 682             return fn(*args, **kwargs)
    683         finally:
    684             self._in_call = False

<decorator-gen-53> in svg(self, line, cell)

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/magics/display.py in svg(self, line, cell)
     58     def svg(self, line, cell):
     59         """Render the cell as an SVG literal"""
---> 60         display(SVG(cell))
     61 
     62     @cell_magic

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/display.py in __init__(self, data, url, filename)
    599                 data = None
    600 
--> 601         self.data = data
    602         self.url = url
    603         self.filename = filename

/home/root/anaconda3/lib/python3.6/site-packages/IPython/core/display.py in data(self, svg)
    705         # parse into dom object
    706         from xml.dom import minidom
--> 707         x = minidom.parseString(svg)
    708         # get svg tag (should be 1)
    709         found_svg = x.getElementsByTagName('svg')

/home/root/anaconda3/lib/python3.6/xml/dom/minidom.py in parseString(string, parser)
   1966     if parser is None:
   1967         from xml.dom import expatbuilder
-> 1968         return expatbuilder.parseString(string)
   1969     else:
   1970         from xml.dom import pulldom

/home/root/anaconda3/lib/python3.6/xml/dom/expatbuilder.py in parseString(string, namespaces)
    923     else:
    924         builder = ExpatBuilder()
--> 925     return builder.parseString(string)
    926 
    927 

/home/root/anaconda3/lib/python3.6/xml/dom/expatbuilder.py in parseString(self, string)
    221         parser = self.getParser()
    222         try:
--> 223             parser.Parse(string, True)
    224             self._setup_subset(string)
    225         except ParseEscape:

ExpatError: unbound prefix: line 12, column 0

ExpatError

ExpatError: unbound prefix: line 12, column 0

Google Suche nach python expaterror unbound prefix ergibt als erstes den Link

Python ElementTree parsing unbound prefix error von Stackoverflow

XML Namespace

XML Namespace ist ebenfalls in einer Spezifikation des W3C festgelegt. Nicht nur, aber auch die Einbindung von SVG in HTML5 hat die Browserhersteller zur Behandlung von Namespaces gezwungen. Das Mozilla Developer Network hat zu Namespaces einen lesenswerten Namespace Crash Course veröffentlicht, insbesondere da er auch die oben beschriebene Problematik behandelt.

Der XLink Namespace xlink ist in der Spezifikation des W3C zur XML Linking Language definiert. Im wesentlichen wird aus dieser Spezifikation nur der simple Link benötigt, der eine URL über das Attribut xlink:href anspricht.

Der Namespace muss dabei über das Attribut xmlns:xlink="http://www.w3.org/1999/xlink" definiert werden

Für SVG Grafiken ist es wichtig zu wissen, dass z.B. bei der Verwendung des <use>-Tags ein Verweis notwendig wird, der nur mit einem href-Attribut aus dem XLink-Namensraum repräsentiert werden kann. Falls also in Jupyter eine SVG Grafik ohne die Definition des Namensraums erfolgt, wird daher ein ExpatError geworfen.

In [2]:
%%SVG
<svg width="140" height="170" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Cat</title>
<desc>Stick Figure of a Cat</desc>

<circle cx="70" cy="95" r="50" style="stroke: black; fill: none;"/>
<circle cx="55" cy="80" r="5" stroke="black" fill="#339933"/>
<circle cx="85" cy="80" r="5" stroke="black" fill="#339933"/>
<g id="whiskers">
   <line x1="75" y1="95" x2="135" y2="85" style="stroke: black;"/>
   <line x1="75" y1="95" x2="135" y2="105" style="stroke: black;"/>
</g>
<use xlink:href="#whiskers" transform="scale(-1 1) translate(-140 0)"/>
<!-- ears -->
<polyline points="108 62,  90 10,  70 45,  50, 10,  32, 62"
   style="stroke: black; fill: none;" />
<!-- mouth -->
<polyline points="35 110, 45 120, 95 120, 105, 110"
    style="stroke: black; fill: none;" />

<!-- nose -->
<path d="M 75 90 L 65 90 A 5 10 0  0 0 75 90"
   style="stroke: black; fill: #ffcccc"/>
<text x="60" y="165" style="font-family: sans-serif; font-size: 14pt;
   stroke: none; fill: black;">Cat</text>
</svg>
Cat Stick Figure of a Cat Cat

Aktives Plenum 2

Erstellen Sie ein SVG Dokument mit folgenden Eigenschaften

  1. Verwenden sie ein Canvas der Größe (300,200)
  2. Erstelle ein Rechteck bei (10,20) mit der Größe (180,120) mit einem roten Rand der Dicke 2 und gelber Füllung
  3. Schreiben sie einen Text in das Rechteck bei (30, 50)
  4. Erweitern sie die Grafik um den nachfolgenden Pfad
  5. Legen sie um den Pfad eine Gruppe mit keinem Rand aber blauer Füllung
  6. und um die Gruppe ein "defs"-Element - was müssen sie bei der Nutzung von "defs" beachten ?
  7. Verwenden sie anschliessend ein "use"-Element um das "defs"-Element zu nutzen
  8. Verwenden sie in dem "use"-Element ein "style"-Attribut mit dem Wert "opacity:0.3"
  9. Verwenden sie anschliessend das "use"-Element nochmal, aber verschieben es um den Vektor (50,70) und skalieren es auf die Hälfte

Pfaddaten

    "M 0.0 112 L 20 124 L 40 129 L 60 126 
    L 80 120 L 100 111 L 120 104 L 140 101
    L 164 106 L 170 103 L 173 80 L 178 60
    L 185 39 L 200 30 L 220 30 L 240 40
    L 260 61 L 280 69 L 290 68 L 288 77
    L 272 85 L 250 85 L 230 85 L 215 88
    L 211 95 L 215 110 L 228 120 L 241 130
    L 251 149 L 252 164 L 242 181 L 221 189
    L 200 191 L 180 193 L 160 192 L 140 190
    L 120 190 L 100 188 L 80 182 L 61 179
    L 42 171 L 30 159 L 13 140 L 00 112 Z"

SVG DOM Beispiel

In [3]:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from xml.dom.minidom import parse, parseString, getDOMImplementation
from xml.dom import DOMException, Node
from urllib.request import urlopen
from IPython.display import SVG

class XMLasDOM():
    
    def __init__(self,xmldocument=None,filename=None):
        if xmldocument:
            if xmldocument.startswith('http'):
                f = urlopen(xmldocument)
                xmldocument = f.read()
            self.document = parseString(xmldocument)
        elif filename:
            self.document = parse(filename)
        else:
            raise ValueError("kein Argument übergeben")
        self.root = self.document.documentElement

table = XMLasDOM("http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/images/table")#'../Beispiele/table.svg')
ellipsen=table.document.documentElement.getElementsByTagName("ellipse")
newText = ["eins","zwei","drei","vier"]
for e in ellipsen:
    print(e.nextSibling.nextSibling.firstChild.data)
    print(newText[ellipsen.index(e)])
    e.nextSibling.nextSibling.firstChild.data = newText[ellipsen.index(e)]
    if ellipsen.index(e) == 2:
        e.nextSibling.nextSibling.setAttribute("y","26.5")
        e.parentNode.removeChild(e.parentNode.getElementsByTagName("text")[1])

SVG(table.document.documentElement.toxml())
Shady Grove
eins
Aeolian
zwei
Over the river,
drei
Dorian
vier
Out[3]:
<table> <tbody> <tr> <tr> <td> <td> <td> <td> eins zwei drei vier

Aktives Plenum 3

  1. Erstellen Sie ein Python DOM Programm, welches das obige SVG Dokument über eine Klasse svgdocument und den 5 Methoden elem, xyElem sowie rect, text und path erstellt.
  2. Erweitern Sie das Programm um die Methode ellipse und erstellen Sie in jedem Eck des Canvas einen zusätzlichen Viertelkreis (zur besseren Visualisierung der Canvas-Fläche
  3. Geben sie das SVG Image als IPython Image mittels der Methode SVG aus dem Modul IPython.display aus