SlideShare ist ein Scribd-Unternehmen logo
1 von 35
1
C. Hetzel, 12. Sept. 2013
Datenbankabfragen über
CSS-Selektoren
Unter Verwendung der CssSelector-Komponente
von Symfony2 Datenbankabfragen gestalten.
Von Carsten Hetzel.
2 C. Hetzel, 12. Sept. 2013
Zur Person
Carsten Hetzel
Seit 2000 in der IT als
Softwareengineer tätig, seit 10
Jahren als Freelancer
Likes: Softwaredesign, SF2
(ach was), BDD mit Behat,
Oracle-Datenbanken
Hobbies: Joggen, Reiten,
Klavierspielen
http://www.coding-inquiries.de
3 C. Hetzel, 12. Sept. 2013
Die Anforderung
Kundenfreundliche Abfragen
großer, strukturierter Datenmengen
4 C. Hetzel, 12. Sept. 2013
Die Anforderung
Für einen Kunden war in einer Browser basierten
Software eine Suchfunktion bereitzustellen, die
beliebigeObjekte einer Objekthierarchie abfragen
und darstellen können sollte.
Probleme:
- Ca. 1 Mio. Objekte.
- Ca. 60 Objekttypen.
- Ca. 16 Mio. Parameter.- Die Suchanfragen mussten für
Laien möglich sein.
5 C. Hetzel, 12. Sept. 2013
Die Anforderung
Beispiel:
Wir wollen alle Objekte X angezeigt bekommen,
die irgendwo unterhalb eines Objekts A hängen
bei dem der Parameter "a" den Wert 10 hat.
6 C. Hetzel, 12. Sept. 2013
Die Idee:
CSS-Selektoren
CSS-Selektoren
7 C. Hetzel, 12. Sept. 2013
Aufbau von CSS-Selektoren
* -> Alle Elemente.
E -> Alle Elemente des Typs "E"
E[foo] -> Alle Elemente des Typs "E", die ein Attribut "foo" besitzen.
E[foo="bar"] -> Alle Elemente des Typs "E", deren Attribut "foo" den Wert "bar" hat.
E#10 -> Alle Elemente des Typs "E", deren Attribut "ID" den Wert 10 hat (entspricht
E[id=10]).
E.myClass -> Alle Elemente des Typs "E", deren Attribut "class" mindestens "myClass"
enthält (entspricht E[class~="myClass"]).
E F -> Alle Elemente des Typs "F", die Nachkommen von "E"-Elementen sind, sich also
irgendwo unterhalb eines E befinden.
E > F -> Alle Elemente des Typs "F", die ein direktes Kind von einem "E"-Element sind.
E, F -> Alle Elemente des Typs "E" und "F".
Siehe: http://www.w3schools.com/cssref/css_selectors.asp oder
http://www.w3.org/TR/2009/CR-CSS2-20090908/selector.html
8 C. Hetzel, 12. Sept. 2013
Die Idee: CSS-Selektoren
Um bestimmte Elemente in einem HTML-Dokument auszuwählen und zu bearbeiten
werden sogenannte CSS-Selektoren verwendet.
Ein solcher Selektor beschreibt den Pfad und die Eigenschaften der Elemente, welche
ausgewählt und durch Zuweisung von Eigenschaftswerten verändert werden sollen.
CSS-Selektoren sind eine einfache Notation für die Auswahl
von Elementen in einem HTML-Dokument.
Ein HTML-Dokument ist eine konkrete hierarchische
Datenstruktur.
Schlussfolgerung: CSS-Selektoren können für beliebige
hierarchische Datenstrukturen verwendet werden.
9 C. Hetzel, 12. Sept. 2013
Die Idee: CSS-Selektoren
Was könnte problematisch sein?
Datenbankmodelle sind nicht notwendigerweise hierarchisch.
Es können nicht (einfach) alle Abfragen, die über SQL
möglich sind, über CSS-Selektoren abgebildet werden.
Beispiel: Selektiere alle Äpfel, die schwerer sind, als die
schwerste Birne.
Oder doch(?): Apfel[gewicht>Birne:max(gewicht)]
10 C. Hetzel, 12. Sept. 2013
Hierarchische Datenstrukturen
und Datenmodelle
und Datenmodelle
Ziel ist, Datenbankabfragen über die Formulierung von Selektoren zu generieren.
Beispiele:
Author
select * from author
Author#1
select * from author where id = 1
Author[lastname=Martin]
select * from author where lastname = 'Martin'
Author[lastname=Martin] Books
select b.* from author a join books b on b.author_id = a.id where a.lastname = 'Martin'
Books[title^=Clean] Author
select a.* from books b join author a on a.id = b.author_id where b.title like 'Clean%'
11 C. Hetzel, 12. Sept. 2013
Hierarchische Datenstrukturen
und Datenmodelle
und Datenmodelle
Wie den einzelnen Beispielen zu entnehmen ist, können Referenzen
in Datenbankmodellen in beiden Richtungen genutzt werden, selbst
wenn die Entitäten, wie in diesem vereinfachten Beispiel, nicht über
eine 1:N-, sondern über eine N:M-Relation verbunden sind. Die
"logische" Hierarchie ergibt sich durch die Wahl der
Selektoren.ACHTUNG: Die "natürliche" Verknüpfung von zwei
Tabellen findet über ihre gegenseitigen Referenzen statt. Trotz dieser
Einschränkung kann es zu großen Ergebnismengen und mehreren
gleichen Ergebnisdatensätzen kommen!
12 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
CssSelector stellt eine
statische Hilfsfunktion zur
Verfügung. Diese baut
lediglich einen Translator
zusammen, der die
eigentliche Arbeit der
Konvertierung des CSS-
Ausdrucks in einen
XPath-Ausdruck
durchführt.
class CssSelector{ public static function toXPath($cssExpr, $prefix =
'descendant-or-self::') { $translator = new Translator(); if (self::
$html) { $translator->registerExtension(new
HtmlExtension($translator)); } $translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser()) ; return $translator-
>cssToXPath($cssExpr, $prefix); } ...}
class CssSelector{ public static function toXPath($cssExpr, $prefix =
'descendant-or-self::') { $translator = new Translator(); if (self::
$html) { $translator->registerExtension(new
HtmlExtension($translator)); } $translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser()) ; return $translator-
>cssToXPath($cssExpr, $prefix); } ...}
13 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Da die Klasse CssSelector primär zur Konvertierung von CSS-
Selektoren zu XPath-Ausdrücken gedacht ist, stelltsie eine
entsprechende Objekthierarchie zusammen. Sie agiert damit als
Fassade zum dahinterliegenden, komplexen Objektstruktur.Der
Translator ist dementsprechend ein XPath-Translator und
verwendet für seine Arbeit die dazugehörigenExtensions und den
eigentlichen Parser.
14 C. Hetzel, 12. Sept. 2013
Intermezzo!
Never use „new“
(unless you‘re supposed to)
15 C. Hetzel, 12. Sept. 2013
Never use „new“
(unless you‘re supposed to)
(unless you‘re supposed to)
Hilft auch ohne Kenntnisse von OO-Prinzipien
und Entwurfsmustern bessere Lösungen
hervor zu bringen
Erzwingt Dependency Injection
Hilft in Komponenten zu denken
Fördert flexibilität und Testbarkeit von Code
Statische Methoden sind KEIN Ersatz!
16 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Da CssSelector als
Fassade dient und die
Komplexität der
interagierenden Objekte
versteckt, ist die
Verwendung von „new“
hier akzeptabel.
Insgesamt ist die
Implementierung nicht
gut, weil sie keine
Einflussnahme auf den
Parsingprozess und die
Konfiguration der Objekte
erlaubt.
class CssSelector{ public static function toXPath($cssExpr, $prefix =
'descendant-or-self::') { $translator = new Translator(); if (self::
$html) { $translator->registerExtension(new
HtmlExtension($translator)); } $translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser()) ; return $translator-
>cssToXPath($cssExpr, $prefix); } ...}
class CssSelector{ public static function toXPath($cssExpr, $prefix =
'descendant-or-self::') { $translator = new Translator(); if (self::
$html) { $translator->registerExtension(new
HtmlExtension($translator)); } $translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser()) ; return $translator-
>cssToXPath($cssExpr, $prefix); } ...}
17 C. Hetzel, 12. Sept. 2013
Die Komponente CssSelector
Probleme, die sich aus der gegebenen Implementierung der
CssSelector-Komponente ergeben:
CssSelector::toXPath() erzeugt eine direkte Abhängigkeit im
Client-Code.
Jeder Aufruf von CssSelector::toXPath() erzeugt alle
verwendeten Objekte neu.
CssSelector ist weder wiederverwendbar, noch erweiterbar.
Aber: toXPath() macht was es soll. ;-)
18 C. Hetzel, 12. Sept. 2013
Die Komponente XPathTranslator
Offensichtlich ist die Komponente XPathTranslator diejenige, die
die eigentliche Arbeit macht.
Verwendet einen Parser, um den CSS-Selektor in eine
Node-Struktur umzuwandeln.
Benutzt Extensions um die verschiedenen NodeTypen
(ElementNode, AttributeNode etc.) in einen XPath-Ausdruck
umzuwandeln.
19 C. Hetzel, 12. Sept. 2013
Der Parser
Der Parser zerteilt über
einen Tokenizer
zunächst den CSS-
Selektor in einzelne
Tokens.
Die Tokens werden
anschließend in
entsprechende Node-
Instanzen umgewandelt
und zurück geliefert.
20 C. Hetzel, 12. Sept. 2013
Die Node-Klassen
Jeder Bestandteil eines
CSS-Selektors wird
durch eine
gleichlautende Klasse
repräsentiert.
Der Parser wandelt also
den Selektor in eine
Objekthierarchie um und
erzeugt dazu die
jeweiligen Instanzen.
21 C. Hetzel, 12. Sept. 2013
XPathTranslator im Detail
Auch hier wird ähnlich wie
bei der XssSelector-
Klasse eine Reihe von
zusätzlichen Hilfsklassen
instanziiert, um die
Verarbeitung in separate
Aufgabenbereiche
aufzutrennen.
Zusätzlilch zur
Konfiguration durch
CssSelector nimmt also
auch noch Translator
selber seine Konfiguration
in die Hand.
class Translator implements TranslatorInterface{ ... public function
__construct(ParserInterface $parser = null) { $this->mainParser =
$parser ?: new Parser(); $this ->registerExtension(new
ExtensionNodeExtension($this)) ->registerExtension(new
ExtensionCombinationExtension()) ->registerExtension(new
ExtensionFunctionExtension()) ->registerExtension(new
ExtensionPseudoClassExtension()) ->registerExtension(new
ExtensionAttributeMatchingExtension()) ; } ...}
class Translator implements TranslatorInterface{ ... public function
__construct(ParserInterface $parser = null) { $this->mainParser =
$parser ?: new Parser(); $this ->registerExtension(new
ExtensionNodeExtension($this)) ->registerExtension(new
ExtensionCombinationExtension()) ->registerExtension(new
ExtensionFunctionExtension()) ->registerExtension(new
ExtensionPseudoClassExtension()) ->registerExtension(new
ExtensionAttributeMatchingExtension()) ; } ...}
22 C. Hetzel, 12. Sept. 2013
XPathTranslator im Detail
In cssToXPath() wird der
Selektor zunächst in
Node-Instanzen
(SelectorNode) und
anschließend über
selectorToXPath() in
einen XPath-Ausdruck
umgewandelt.
class Translator implements TranslatorInterface{ ... public function
cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors =
$this->parseSelectors($cssExpr); /** @var SelectorNode $selector */
foreach ($selectors as $selector) { if (null !== $selector-
>getPseudoElement()) { throw new
ExpressionErrorException('Pseudo-elements are not supported.'); }
} $translator = $this; return implode(' | ', array_map(function
(SelectorNode $selector) use ($translator, $prefix) { return
$translator->selectorToXPath($selector, $prefix); },
$selectors)); } ...}
class Translator implements TranslatorInterface{ ... public function
cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors =
$this->parseSelectors($cssExpr); /** @var SelectorNode $selector */
foreach ($selectors as $selector) { if (null !== $selector-
>getPseudoElement()) { throw new
ExpressionErrorException('Pseudo-elements are not supported.'); }
} $translator = $this; return implode(' | ', array_map(function
(SelectorNode $selector) use ($translator, $prefix) { return
$translator->selectorToXPath($selector, $prefix); },
$selectors)); } ...}
23 C. Hetzel, 12. Sept. 2013
Die Extension-Klassen
Jede Extension-Klasse
ist dafür zuständig, die
für sie relevanten Node-
Instanzen in einen
XPath-Ausdruck
umzuwnadeln.
Dabei werden vom
Translator die dazu
registrierten Methoden
aufgerufen.
24 C. Hetzel, 12. Sept. 2013
XPathExtensions im Detail
Der Vorgang lässt sich
anschaulich an der
Umsetzung der
„HashNode“ zeigen: Ein
Ausdruck wie „Author#1“
soll das Element mit der
ID „1“.
Die HashNode hat eine
SelectorNode und die
gewünschte ID. Beide
Bestandteile werden vom
Translator in den finalen
XPath-Ausdruck
konvertiert.
class NodeExtension extends AbstractExtension{ ... public function
translateHash(NodeHashNode $node) { $xpath = $this->translator-
>nodeToXPath($node->getSelector()); return $this->translator-
>addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...}
class NodeExtension extends AbstractExtension{ ... public function
translateHash(NodeHashNode $node) { $xpath = $this->translator-
>nodeToXPath($node->getSelector()); return $this->translator-
>addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...}
class AttributeMatchingExtension extends AbstractExtension{ ... public
function translateEquals(XPathExpr $xpath, $attribute, $value)
{ return $xpath->addCondition(sprintf('%s = %s', $attribute,
Translator::getXpathLiteral($value))); } ...}
class AttributeMatchingExtension extends AbstractExtension{ ... public
function translateEquals(XPathExpr $xpath, $attribute, $value)
{ return $xpath->addCondition(sprintf('%s = %s', $attribute,
Translator::getXpathLiteral($value))); } ...}
25 C. Hetzel, 12. Sept. 2013
CSS-Selektoren für
Datenbankstatements
Als Datenbankschicht wurde das ORM Propel
verwendet - es lassen sich aber auch andere
ORMs oder DBALs wie z.B. Doctrine
verwenden.
Die Realisierung des Translators wurde an
XPathTranslator angelehnt.
Das Datenmodell besteht aus Authoren und
Büchern mit einer 1:N-Beziehung.
26 C. Hetzel, 12. Sept. 2013
Die Implementierung auf
einen Blick
Es wurde eine einfache Symfony2
Anwendung generiert mit Controllern
zu Book und Author.
Der DbQueryTranslator wandelt den
CSS-Selektor in ein ModelCriteria-
Objekt um - entweder vom Typ
AuthorQuery oder BookQuery.
Die Extensions sind dafür zuständig
die API der Propel-Query-Klassen
anzusprechen.
27 C. Hetzel, 12. Sept. 2013
DbQueryTranslator im Detail
Der DbQueryTranslator
orientiert sich am
XPathTranslator (und macht die
gleichen Fehler).
Damit die NodeExtension die
richtigen Model-Klassen finden
kann, benötigt sie deren
Namespace.
Der Rest funktioniert analog:
Parsen des Selektors und
Umwandeln der Nodes in ein
ModelCriteria (bzw.
AuthorQuery oder BookQuery).
class Translator{ public function __construct( ParserInterface $parser =
null ) { $this->mainParser = $parser ? : new Parser();
$modelNS = 'AppDbModelSelectorBundleModel';
$this->registerExtension(
new ExtensionNodeExtension( $this, null,
$modelNS ) ) ->registerExtension(
new ExtensionCombinationExtension() )
->registerExtension(
new ExtensionAttributeMatchingExtension() );
} public function cssToDbQuery( $cssExpr ) {
$selectors = $this->parseSelectors( $cssExpr );
$query = null; foreach( $selectors as $selector ){
$query = $this->selectorToDbQuery( $selector, $query );
} return $query; }
...}
class Translator{ public function __construct( ParserInterface $parser =
null ) { $this->mainParser = $parser ? : new Parser();
$modelNS = 'AppDbModelSelectorBundleModel';
$this->registerExtension(
new ExtensionNodeExtension( $this, null,
$modelNS ) ) ->registerExtension(
new ExtensionCombinationExtension() )
->registerExtension(
new ExtensionAttributeMatchingExtension() );
} public function cssToDbQuery( $cssExpr ) {
$selectors = $this->parseSelectors( $cssExpr );
$query = null; foreach( $selectors as $selector ){
$query = $this->selectorToDbQuery( $selector, $query );
} return $query; }
...}
28 C. Hetzel, 12. Sept. 2013
Extensions im Detail
Basis für alle weiteren
Operationen ist ein Query-
Objekt des gewünschten
Models.
Dazu wird der Name der
ElementNode ermittelt und im
Namespace der Models geprüft,
ob es eine passende Klasse
gibt, also AuthorQuery oder
BookQuery gesucht.
Query-Klassen werden bei
Propel über die Statische
„create()“-Methode erzeugt.
class NodeExtension extends AbstractExtension{ public function
translateElement( NodeElementNode $node ) {
$element = $node->getElement(); $queryClassName = $this-
>modelNamespace . $element . 'Query'; if( !
class_exists( $queryClassName ) ) throw new
RuntimeException( sprintf( 'Model %s not supported!', $queryClassName )
); return $queryClassName::create(); }
...}
class NodeExtension extends AbstractExtension{ public function
translateElement( NodeElementNode $node ) {
$element = $node->getElement(); $queryClassName = $this-
>modelNamespace . $element . 'Query'; if( !
class_exists( $queryClassName ) ) throw new
RuntimeException( sprintf( 'Model %s not supported!', $queryClassName )
); return $queryClassName::create(); }
...}
29 C. Hetzel, 12. Sept. 2013
Extensions im Detail
Hier als Beispiel noch die
Implementierung für
AttributeNodes, mit denen
where-Bedingungen für die
Datenbank erzeugt werden.
Die SelectorNode kapselt dabei
wieder den Zugriff auf die
Datenbanktabelle, die
AttributeNode die Bedingungen
für einzelne Spalten der Tabelle.
class NodeExtension extends AbstractExtension{
... public function translateAttribute( NodeAttributeNode
$node ) { $attribute = $node->getAttribute();
$operator = $node->getOperator(); $value = $node->getValue();
$query = $this->translator-
>nodeToDbQuery( $node->getSelector() ); return $this-
>translator->addAttributeMatching(
$query,
$operator,
$attribute,
$value ); } ...}
class NodeExtension extends AbstractExtension{
... public function translateAttribute( NodeAttributeNode
$node ) { $attribute = $node->getAttribute();
$operator = $node->getOperator(); $value = $node->getValue();
$query = $this->translator-
>nodeToDbQuery( $node->getSelector() ); return $this-
>translator->addAttributeMatching(
$query,
$operator,
$attribute,
$value ); } ...}
30 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Über den CssSelector
„Author“ werden alle
Authoren angezeigt.
Er kann alternativ
auch weggelassen
werden.
In den Beispieldaten
hat Robert Martin zwei
Bücher und Martin
Fowler eines.
31 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Durch den Join mit Books
wird somit Robert Martin
zweimal angezeigt.
Der Translator wäre
nützlicherweise so
anzupassen, dass er
einen Pseudoknoten
„distinct“ erlaubt, um
diesen Effekt zu
vermeidenn.
32 C. Hetzel, 12. Sept. 2013
Die Anwendung in
Bildern
Wie man dem Profiler entnehmen kann, werden die korrekten
Datenbankabfragen generiert.
Der Selector „Book[title*=Coder] Author[Lastname=Martin]“ wurde
umgesetzt.
33 C. Hetzel, 12. Sept. 2013
Ausblick
Zusätzliche Funktionalitäten wie „distinct“ oder
Aggregatfunktionen sind denkbar.
Virtuelle Attribute wie „Book.count()“ können
realisiert werden.
Bei bestimmten Zugriffen können Hints für den
Ausführungsplan ergänzt werden.
...
34 C. Hetzel, 12. Sept. 2013
Fragen? ;-)
35 C. Hetzel, 12. Sept. 2013
Vielen Dank für Ihre
Aufmerksamkeit!

Weitere ähnliche Inhalte

Ähnlich wie 2013-09-12, sfugcgn: CSS-Selektoren für Datenbankabfragen nutzen

Tell, Don't Ask - Aussagekräftige Schnittstellen
Tell, Don't Ask  - Aussagekräftige SchnittstellenTell, Don't Ask  - Aussagekräftige Schnittstellen
Tell, Don't Ask - Aussagekräftige SchnittstellenCarsten Hetzel
 
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Nils Adermann
 
Dynamische Websites mit XML
Dynamische Websites mit XMLDynamische Websites mit XML
Dynamische Websites mit XMLStephan Schmidt
 
Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Sebastian Adler
 
Dependency Injection - A practical introduction
Dependency Injection - A practical introductionDependency Injection - A practical introduction
Dependency Injection - A practical introductionCarsten Hetzel
 
Dart (Teil II der Tour de Dart)
Dart (Teil II der Tour de Dart)Dart (Teil II der Tour de Dart)
Dart (Teil II der Tour de Dart)Nane Kratzke
 
Einführung in Elasticsearch
Einführung in ElasticsearchEinführung in Elasticsearch
Einführung in ElasticsearchFlorian Hopf
 
Data model mal anders
Data model mal andersData model mal anders
Data model mal andersMaxim Zaks
 
Workshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GAWorkshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GAOliver Belikan
 
MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)Uwe Printz
 
Einführung in Elasticsearch
Einführung in ElasticsearchEinführung in Elasticsearch
Einführung in ElasticsearchFlorian Hopf
 
Object-orientied way of using mysqli interface - Workshop
Object-orientied way of using mysqli interface - WorkshopObject-orientied way of using mysqli interface - Workshop
Object-orientied way of using mysqli interface - WorkshopWaldemar Dell
 
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)Java Usergroup Berlin-Brandenburg
 
Einfuehrung in Elasticsearch
Einfuehrung in ElasticsearchEinfuehrung in Elasticsearch
Einfuehrung in ElasticsearchFlorian Hopf
 
Anforderungsanalsyse - Prototyping mit JavaScript
Anforderungsanalsyse - Prototyping mit JavaScriptAnforderungsanalsyse - Prototyping mit JavaScript
Anforderungsanalsyse - Prototyping mit JavaScriptChristian Baranowski
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7msebel
 

Ähnlich wie 2013-09-12, sfugcgn: CSS-Selektoren für Datenbankabfragen nutzen (20)

Tell, Don't Ask - Aussagekräftige Schnittstellen
Tell, Don't Ask  - Aussagekräftige SchnittstellenTell, Don't Ask  - Aussagekräftige Schnittstellen
Tell, Don't Ask - Aussagekräftige Schnittstellen
 
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
Apache CouchDB at PHPUG Karlsruhe, Germany (Jan 27th 2009)
 
Dynamische Websites mit XML
Dynamische Websites mit XMLDynamische Websites mit XML
Dynamische Websites mit XML
 
Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)Einstieg in Xpath für SEO (Campixx2021)
Einstieg in Xpath für SEO (Campixx2021)
 
Spark vs. PL/SQL
Spark vs. PL/SQLSpark vs. PL/SQL
Spark vs. PL/SQL
 
Dependency Injection - A practical introduction
Dependency Injection - A practical introductionDependency Injection - A practical introduction
Dependency Injection - A practical introduction
 
Dart (Teil II der Tour de Dart)
Dart (Teil II der Tour de Dart)Dart (Teil II der Tour de Dart)
Dart (Teil II der Tour de Dart)
 
Einführung in Elasticsearch
Einführung in ElasticsearchEinführung in Elasticsearch
Einführung in Elasticsearch
 
Data model mal anders
Data model mal andersData model mal anders
Data model mal anders
 
Workshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GAWorkshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GA
 
MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)MongoDB für Java Programmierer (JUGKA, 11.12.13)
MongoDB für Java Programmierer (JUGKA, 11.12.13)
 
Einführung in Elasticsearch
Einführung in ElasticsearchEinführung in Elasticsearch
Einführung in Elasticsearch
 
jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?
 
Object-orientied way of using mysqli interface - Workshop
Object-orientied way of using mysqli interface - WorkshopObject-orientied way of using mysqli interface - Workshop
Object-orientied way of using mysqli interface - Workshop
 
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)
Die fabelhafte Welt Java(Script)-getriebener Enterprise-WebApps (mit Ext JS)
 
JavaScript Performance
JavaScript PerformanceJavaScript Performance
JavaScript Performance
 
CSS Clean Code
CSS Clean CodeCSS Clean Code
CSS Clean Code
 
Einfuehrung in Elasticsearch
Einfuehrung in ElasticsearchEinfuehrung in Elasticsearch
Einfuehrung in Elasticsearch
 
Anforderungsanalsyse - Prototyping mit JavaScript
Anforderungsanalsyse - Prototyping mit JavaScriptAnforderungsanalsyse - Prototyping mit JavaScript
Anforderungsanalsyse - Prototyping mit JavaScript
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
 

2013-09-12, sfugcgn: CSS-Selektoren für Datenbankabfragen nutzen

  • 1. 1 C. Hetzel, 12. Sept. 2013 Datenbankabfragen über CSS-Selektoren Unter Verwendung der CssSelector-Komponente von Symfony2 Datenbankabfragen gestalten. Von Carsten Hetzel.
  • 2. 2 C. Hetzel, 12. Sept. 2013 Zur Person Carsten Hetzel Seit 2000 in der IT als Softwareengineer tätig, seit 10 Jahren als Freelancer Likes: Softwaredesign, SF2 (ach was), BDD mit Behat, Oracle-Datenbanken Hobbies: Joggen, Reiten, Klavierspielen http://www.coding-inquiries.de
  • 3. 3 C. Hetzel, 12. Sept. 2013 Die Anforderung Kundenfreundliche Abfragen großer, strukturierter Datenmengen
  • 4. 4 C. Hetzel, 12. Sept. 2013 Die Anforderung Für einen Kunden war in einer Browser basierten Software eine Suchfunktion bereitzustellen, die beliebigeObjekte einer Objekthierarchie abfragen und darstellen können sollte. Probleme: - Ca. 1 Mio. Objekte. - Ca. 60 Objekttypen. - Ca. 16 Mio. Parameter.- Die Suchanfragen mussten für Laien möglich sein.
  • 5. 5 C. Hetzel, 12. Sept. 2013 Die Anforderung Beispiel: Wir wollen alle Objekte X angezeigt bekommen, die irgendwo unterhalb eines Objekts A hängen bei dem der Parameter "a" den Wert 10 hat.
  • 6. 6 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren CSS-Selektoren
  • 7. 7 C. Hetzel, 12. Sept. 2013 Aufbau von CSS-Selektoren * -> Alle Elemente. E -> Alle Elemente des Typs "E" E[foo] -> Alle Elemente des Typs "E", die ein Attribut "foo" besitzen. E[foo="bar"] -> Alle Elemente des Typs "E", deren Attribut "foo" den Wert "bar" hat. E#10 -> Alle Elemente des Typs "E", deren Attribut "ID" den Wert 10 hat (entspricht E[id=10]). E.myClass -> Alle Elemente des Typs "E", deren Attribut "class" mindestens "myClass" enthält (entspricht E[class~="myClass"]). E F -> Alle Elemente des Typs "F", die Nachkommen von "E"-Elementen sind, sich also irgendwo unterhalb eines E befinden. E > F -> Alle Elemente des Typs "F", die ein direktes Kind von einem "E"-Element sind. E, F -> Alle Elemente des Typs "E" und "F". Siehe: http://www.w3schools.com/cssref/css_selectors.asp oder http://www.w3.org/TR/2009/CR-CSS2-20090908/selector.html
  • 8. 8 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren Um bestimmte Elemente in einem HTML-Dokument auszuwählen und zu bearbeiten werden sogenannte CSS-Selektoren verwendet. Ein solcher Selektor beschreibt den Pfad und die Eigenschaften der Elemente, welche ausgewählt und durch Zuweisung von Eigenschaftswerten verändert werden sollen. CSS-Selektoren sind eine einfache Notation für die Auswahl von Elementen in einem HTML-Dokument. Ein HTML-Dokument ist eine konkrete hierarchische Datenstruktur. Schlussfolgerung: CSS-Selektoren können für beliebige hierarchische Datenstrukturen verwendet werden.
  • 9. 9 C. Hetzel, 12. Sept. 2013 Die Idee: CSS-Selektoren Was könnte problematisch sein? Datenbankmodelle sind nicht notwendigerweise hierarchisch. Es können nicht (einfach) alle Abfragen, die über SQL möglich sind, über CSS-Selektoren abgebildet werden. Beispiel: Selektiere alle Äpfel, die schwerer sind, als die schwerste Birne. Oder doch(?): Apfel[gewicht>Birne:max(gewicht)]
  • 10. 10 C. Hetzel, 12. Sept. 2013 Hierarchische Datenstrukturen und Datenmodelle und Datenmodelle Ziel ist, Datenbankabfragen über die Formulierung von Selektoren zu generieren. Beispiele: Author select * from author Author#1 select * from author where id = 1 Author[lastname=Martin] select * from author where lastname = 'Martin' Author[lastname=Martin] Books select b.* from author a join books b on b.author_id = a.id where a.lastname = 'Martin' Books[title^=Clean] Author select a.* from books b join author a on a.id = b.author_id where b.title like 'Clean%'
  • 11. 11 C. Hetzel, 12. Sept. 2013 Hierarchische Datenstrukturen und Datenmodelle und Datenmodelle Wie den einzelnen Beispielen zu entnehmen ist, können Referenzen in Datenbankmodellen in beiden Richtungen genutzt werden, selbst wenn die Entitäten, wie in diesem vereinfachten Beispiel, nicht über eine 1:N-, sondern über eine N:M-Relation verbunden sind. Die "logische" Hierarchie ergibt sich durch die Wahl der Selektoren.ACHTUNG: Die "natürliche" Verknüpfung von zwei Tabellen findet über ihre gegenseitigen Referenzen statt. Trotz dieser Einschränkung kann es zu großen Ergebnismengen und mehreren gleichen Ergebnisdatensätzen kommen!
  • 12. 12 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector CssSelector stellt eine statische Hilfsfunktion zur Verfügung. Diese baut lediglich einen Translator zusammen, der die eigentliche Arbeit der Konvertierung des CSS- Ausdrucks in einen XPath-Ausdruck durchführt. class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...} class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...}
  • 13. 13 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Da die Klasse CssSelector primär zur Konvertierung von CSS- Selektoren zu XPath-Ausdrücken gedacht ist, stelltsie eine entsprechende Objekthierarchie zusammen. Sie agiert damit als Fassade zum dahinterliegenden, komplexen Objektstruktur.Der Translator ist dementsprechend ein XPath-Translator und verwendet für seine Arbeit die dazugehörigenExtensions und den eigentlichen Parser.
  • 14. 14 C. Hetzel, 12. Sept. 2013 Intermezzo! Never use „new“ (unless you‘re supposed to)
  • 15. 15 C. Hetzel, 12. Sept. 2013 Never use „new“ (unless you‘re supposed to) (unless you‘re supposed to) Hilft auch ohne Kenntnisse von OO-Prinzipien und Entwurfsmustern bessere Lösungen hervor zu bringen Erzwingt Dependency Injection Hilft in Komponenten zu denken Fördert flexibilität und Testbarkeit von Code Statische Methoden sind KEIN Ersatz!
  • 16. 16 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Da CssSelector als Fassade dient und die Komplexität der interagierenden Objekte versteckt, ist die Verwendung von „new“ hier akzeptabel. Insgesamt ist die Implementierung nicht gut, weil sie keine Einflussnahme auf den Parsingprozess und die Konfiguration der Objekte erlaubt. class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...} class CssSelector{ public static function toXPath($cssExpr, $prefix = 'descendant-or-self::') { $translator = new Translator(); if (self:: $html) { $translator->registerExtension(new HtmlExtension($translator)); } $translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; return $translator- >cssToXPath($cssExpr, $prefix); } ...}
  • 17. 17 C. Hetzel, 12. Sept. 2013 Die Komponente CssSelector Probleme, die sich aus der gegebenen Implementierung der CssSelector-Komponente ergeben: CssSelector::toXPath() erzeugt eine direkte Abhängigkeit im Client-Code. Jeder Aufruf von CssSelector::toXPath() erzeugt alle verwendeten Objekte neu. CssSelector ist weder wiederverwendbar, noch erweiterbar. Aber: toXPath() macht was es soll. ;-)
  • 18. 18 C. Hetzel, 12. Sept. 2013 Die Komponente XPathTranslator Offensichtlich ist die Komponente XPathTranslator diejenige, die die eigentliche Arbeit macht. Verwendet einen Parser, um den CSS-Selektor in eine Node-Struktur umzuwandeln. Benutzt Extensions um die verschiedenen NodeTypen (ElementNode, AttributeNode etc.) in einen XPath-Ausdruck umzuwandeln.
  • 19. 19 C. Hetzel, 12. Sept. 2013 Der Parser Der Parser zerteilt über einen Tokenizer zunächst den CSS- Selektor in einzelne Tokens. Die Tokens werden anschließend in entsprechende Node- Instanzen umgewandelt und zurück geliefert.
  • 20. 20 C. Hetzel, 12. Sept. 2013 Die Node-Klassen Jeder Bestandteil eines CSS-Selektors wird durch eine gleichlautende Klasse repräsentiert. Der Parser wandelt also den Selektor in eine Objekthierarchie um und erzeugt dazu die jeweiligen Instanzen.
  • 21. 21 C. Hetzel, 12. Sept. 2013 XPathTranslator im Detail Auch hier wird ähnlich wie bei der XssSelector- Klasse eine Reihe von zusätzlichen Hilfsklassen instanziiert, um die Verarbeitung in separate Aufgabenbereiche aufzutrennen. Zusätzlilch zur Konfiguration durch CssSelector nimmt also auch noch Translator selber seine Konfiguration in die Hand. class Translator implements TranslatorInterface{ ... public function __construct(ParserInterface $parser = null) { $this->mainParser = $parser ?: new Parser(); $this ->registerExtension(new ExtensionNodeExtension($this)) ->registerExtension(new ExtensionCombinationExtension()) ->registerExtension(new ExtensionFunctionExtension()) ->registerExtension(new ExtensionPseudoClassExtension()) ->registerExtension(new ExtensionAttributeMatchingExtension()) ; } ...} class Translator implements TranslatorInterface{ ... public function __construct(ParserInterface $parser = null) { $this->mainParser = $parser ?: new Parser(); $this ->registerExtension(new ExtensionNodeExtension($this)) ->registerExtension(new ExtensionCombinationExtension()) ->registerExtension(new ExtensionFunctionExtension()) ->registerExtension(new ExtensionPseudoClassExtension()) ->registerExtension(new ExtensionAttributeMatchingExtension()) ; } ...}
  • 22. 22 C. Hetzel, 12. Sept. 2013 XPathTranslator im Detail In cssToXPath() wird der Selektor zunächst in Node-Instanzen (SelectorNode) und anschließend über selectorToXPath() in einen XPath-Ausdruck umgewandelt. class Translator implements TranslatorInterface{ ... public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors = $this->parseSelectors($cssExpr); /** @var SelectorNode $selector */ foreach ($selectors as $selector) { if (null !== $selector- >getPseudoElement()) { throw new ExpressionErrorException('Pseudo-elements are not supported.'); } } $translator = $this; return implode(' | ', array_map(function (SelectorNode $selector) use ($translator, $prefix) { return $translator->selectorToXPath($selector, $prefix); }, $selectors)); } ...} class Translator implements TranslatorInterface{ ... public function cssToXPath($cssExpr, $prefix = 'descendant-or-self::') { $selectors = $this->parseSelectors($cssExpr); /** @var SelectorNode $selector */ foreach ($selectors as $selector) { if (null !== $selector- >getPseudoElement()) { throw new ExpressionErrorException('Pseudo-elements are not supported.'); } } $translator = $this; return implode(' | ', array_map(function (SelectorNode $selector) use ($translator, $prefix) { return $translator->selectorToXPath($selector, $prefix); }, $selectors)); } ...}
  • 23. 23 C. Hetzel, 12. Sept. 2013 Die Extension-Klassen Jede Extension-Klasse ist dafür zuständig, die für sie relevanten Node- Instanzen in einen XPath-Ausdruck umzuwnadeln. Dabei werden vom Translator die dazu registrierten Methoden aufgerufen.
  • 24. 24 C. Hetzel, 12. Sept. 2013 XPathExtensions im Detail Der Vorgang lässt sich anschaulich an der Umsetzung der „HashNode“ zeigen: Ein Ausdruck wie „Author#1“ soll das Element mit der ID „1“. Die HashNode hat eine SelectorNode und die gewünschte ID. Beide Bestandteile werden vom Translator in den finalen XPath-Ausdruck konvertiert. class NodeExtension extends AbstractExtension{ ... public function translateHash(NodeHashNode $node) { $xpath = $this->translator- >nodeToXPath($node->getSelector()); return $this->translator- >addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...} class NodeExtension extends AbstractExtension{ ... public function translateHash(NodeHashNode $node) { $xpath = $this->translator- >nodeToXPath($node->getSelector()); return $this->translator- >addAttributeMatching($xpath, '=', '@id', $node->getId()); } ...} class AttributeMatchingExtension extends AbstractExtension{ ... public function translateEquals(XPathExpr $xpath, $attribute, $value) { return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); } ...} class AttributeMatchingExtension extends AbstractExtension{ ... public function translateEquals(XPathExpr $xpath, $attribute, $value) { return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); } ...}
  • 25. 25 C. Hetzel, 12. Sept. 2013 CSS-Selektoren für Datenbankstatements Als Datenbankschicht wurde das ORM Propel verwendet - es lassen sich aber auch andere ORMs oder DBALs wie z.B. Doctrine verwenden. Die Realisierung des Translators wurde an XPathTranslator angelehnt. Das Datenmodell besteht aus Authoren und Büchern mit einer 1:N-Beziehung.
  • 26. 26 C. Hetzel, 12. Sept. 2013 Die Implementierung auf einen Blick Es wurde eine einfache Symfony2 Anwendung generiert mit Controllern zu Book und Author. Der DbQueryTranslator wandelt den CSS-Selektor in ein ModelCriteria- Objekt um - entweder vom Typ AuthorQuery oder BookQuery. Die Extensions sind dafür zuständig die API der Propel-Query-Klassen anzusprechen.
  • 27. 27 C. Hetzel, 12. Sept. 2013 DbQueryTranslator im Detail Der DbQueryTranslator orientiert sich am XPathTranslator (und macht die gleichen Fehler). Damit die NodeExtension die richtigen Model-Klassen finden kann, benötigt sie deren Namespace. Der Rest funktioniert analog: Parsen des Selektors und Umwandeln der Nodes in ein ModelCriteria (bzw. AuthorQuery oder BookQuery). class Translator{ public function __construct( ParserInterface $parser = null ) { $this->mainParser = $parser ? : new Parser(); $modelNS = 'AppDbModelSelectorBundleModel'; $this->registerExtension( new ExtensionNodeExtension( $this, null, $modelNS ) ) ->registerExtension( new ExtensionCombinationExtension() ) ->registerExtension( new ExtensionAttributeMatchingExtension() ); } public function cssToDbQuery( $cssExpr ) { $selectors = $this->parseSelectors( $cssExpr ); $query = null; foreach( $selectors as $selector ){ $query = $this->selectorToDbQuery( $selector, $query ); } return $query; } ...} class Translator{ public function __construct( ParserInterface $parser = null ) { $this->mainParser = $parser ? : new Parser(); $modelNS = 'AppDbModelSelectorBundleModel'; $this->registerExtension( new ExtensionNodeExtension( $this, null, $modelNS ) ) ->registerExtension( new ExtensionCombinationExtension() ) ->registerExtension( new ExtensionAttributeMatchingExtension() ); } public function cssToDbQuery( $cssExpr ) { $selectors = $this->parseSelectors( $cssExpr ); $query = null; foreach( $selectors as $selector ){ $query = $this->selectorToDbQuery( $selector, $query ); } return $query; } ...}
  • 28. 28 C. Hetzel, 12. Sept. 2013 Extensions im Detail Basis für alle weiteren Operationen ist ein Query- Objekt des gewünschten Models. Dazu wird der Name der ElementNode ermittelt und im Namespace der Models geprüft, ob es eine passende Klasse gibt, also AuthorQuery oder BookQuery gesucht. Query-Klassen werden bei Propel über die Statische „create()“-Methode erzeugt. class NodeExtension extends AbstractExtension{ public function translateElement( NodeElementNode $node ) { $element = $node->getElement(); $queryClassName = $this- >modelNamespace . $element . 'Query'; if( ! class_exists( $queryClassName ) ) throw new RuntimeException( sprintf( 'Model %s not supported!', $queryClassName ) ); return $queryClassName::create(); } ...} class NodeExtension extends AbstractExtension{ public function translateElement( NodeElementNode $node ) { $element = $node->getElement(); $queryClassName = $this- >modelNamespace . $element . 'Query'; if( ! class_exists( $queryClassName ) ) throw new RuntimeException( sprintf( 'Model %s not supported!', $queryClassName ) ); return $queryClassName::create(); } ...}
  • 29. 29 C. Hetzel, 12. Sept. 2013 Extensions im Detail Hier als Beispiel noch die Implementierung für AttributeNodes, mit denen where-Bedingungen für die Datenbank erzeugt werden. Die SelectorNode kapselt dabei wieder den Zugriff auf die Datenbanktabelle, die AttributeNode die Bedingungen für einzelne Spalten der Tabelle. class NodeExtension extends AbstractExtension{ ... public function translateAttribute( NodeAttributeNode $node ) { $attribute = $node->getAttribute(); $operator = $node->getOperator(); $value = $node->getValue(); $query = $this->translator- >nodeToDbQuery( $node->getSelector() ); return $this- >translator->addAttributeMatching( $query, $operator, $attribute, $value ); } ...} class NodeExtension extends AbstractExtension{ ... public function translateAttribute( NodeAttributeNode $node ) { $attribute = $node->getAttribute(); $operator = $node->getOperator(); $value = $node->getValue(); $query = $this->translator- >nodeToDbQuery( $node->getSelector() ); return $this- >translator->addAttributeMatching( $query, $operator, $attribute, $value ); } ...}
  • 30. 30 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Über den CssSelector „Author“ werden alle Authoren angezeigt. Er kann alternativ auch weggelassen werden. In den Beispieldaten hat Robert Martin zwei Bücher und Martin Fowler eines.
  • 31. 31 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Durch den Join mit Books wird somit Robert Martin zweimal angezeigt. Der Translator wäre nützlicherweise so anzupassen, dass er einen Pseudoknoten „distinct“ erlaubt, um diesen Effekt zu vermeidenn.
  • 32. 32 C. Hetzel, 12. Sept. 2013 Die Anwendung in Bildern Wie man dem Profiler entnehmen kann, werden die korrekten Datenbankabfragen generiert. Der Selector „Book[title*=Coder] Author[Lastname=Martin]“ wurde umgesetzt.
  • 33. 33 C. Hetzel, 12. Sept. 2013 Ausblick Zusätzliche Funktionalitäten wie „distinct“ oder Aggregatfunktionen sind denkbar. Virtuelle Attribute wie „Book.count()“ können realisiert werden. Bei bestimmten Zugriffen können Hints für den Ausführungsplan ergänzt werden. ...
  • 34. 34 C. Hetzel, 12. Sept. 2013 Fragen? ;-)
  • 35. 35 C. Hetzel, 12. Sept. 2013 Vielen Dank für Ihre Aufmerksamkeit!

Hinweis der Redaktion

  1. Hinweis: Dieses Problem ist einfach, weil es von einer festen Hierarchie ausgeht! Hinweis: Die Auswahl der darzustellenden Objekte kann nicht PHP-seitig stattfinden, denn dafür ist die Datenmenge zu groß.
  2. Vereinfachung: Author und Buch haben eine 1:N-Relation Was fällt am letzten Statement auf? Es kann der selbe Author mehrfach in der Ergebnismenge auftreten! Hier wäre ein „distinct“ nötig, etwa: Books[title^=Clean] Author.distinct()
  3. Hinweise: - Die XPath\Translator-Komponente bietet z.B. über den Konstruktor einen anderen Parser zu verwenden. Dem Anwender von CssSelector wird aber keine Möglichkeit geboten einen anderen Parser zu injizieren! - Auf diese Weise kann weder in den Parsing-Prozess eingegriffen, noch dezidiert auf Ereignisse reagiert werden!
  4. Hinweise: - Die XPath\Translator-Komponente bietet z.B. über den Konstruktor einen anderen Parser zu verwenden. Dem Anwender von CssSelector wird aber keine Möglichkeit geboten einen anderen Parser zu injizieren! - Auf diese Weise kann weder in den Parsing-Prozess eingegriffen, noch dezidiert auf Ereignisse reagiert werden!
  5. Anmerkung: Ist noch jemand bei mir?