Librairies Plist ?

yoannyoann Membre
01:43 modifié dans Langages Web & serveurs #1
Une fois n'est pas coutume je vais un peut oublier le NDA de la WWDC pour un sujet bien précis, les échanges client/serveur pour vos applications iPhone (et Mac aussi).

Une jolie présentation nous a était faite pour présenter les différences de temps de chargement entre XML, JSON, Plist et Plist binaire sur l'iPhone.

Pour résumer, les temps de téléchargement sont quasi identique pour JSON, Plist et Plist binaire et bien plus élevé pour XML. Quant au temps de chargement des données (pour en faire un truc utilisable en code), elles sont énormes en XML bien entendu, en JSON acceptable, Plist standard plus rapide que JSON et Plist binaire carrément infime, et pour cause c'est prévu pour être utilisé par NSDictionary et NSArray directement.

Pour les formats Plist la présentation disaient d'utiliser WebObject pour les gérer aussi simplement que sur le client (ndlr. en une seule ligne de code que ce soit pour l'import ou l'export) ou de voir des lib alternative qui existe.

Ma question est donc, que connaissez vous comme lib capable de sortir du Plist sur un web service ou encore mieux, du plist binaire ? Cela pourrait être intéressant de se constituer une liste comparative de ces librairies.

Pour ma part je n'en connait pas pour le moment :-/

Réponses

  • muqaddarmuqaddar Administrateur
    juin 2010 modifié #2
    Il existe un plugin Rails apparemment :
    http://plist.rubyforge.org/

    En binaire ça va être plus dur... puisque le but n'est pas de le compresser après téléchargement hein... mais sur le serveur.

    En revanche, je suis étonné qu'un PLIST standard soit plus rapide que le JSON ?
  • muqaddarmuqaddar Administrateur
    01:43 modifié #3
    Ah bein non, j'ai trouvé bien mieux !!!

    http://jeena.net/
    http://github.com/jeena/plistifier

    C'est malin ça, moi qui suit en train d'attaquer ma synchro en JSON, je fais quoi maintenant ?  >:)
  • AliGatorAliGator Membre, Modérateur
    01:43 modifié #4
    Tiens, le projet que tu cites Alex se base sur un autre projet Ruby "CFPropertyList"... qui sait générer des Plist Binaires !
    Or il me semblait que le format binaire des Plist était un peu obscur, en tout cas non documenté (genre format fermé), j'ai pas souvenir d'avoir la spec (justement pour si on veut implémenter ça dans d'autres langages côté serveur)... des infos sur ce format binaire ?
  • muqaddarmuqaddar Administrateur
    juin 2010 modifié #5
    Et un PLIST binaire, on le charge avec quoi du coup ?
    Il n'y a pas de fonction type initWithContentsOfURLForBinaryPlist ?

    Yoann a l'air de dire que NSArray sait les lire directement les binaires ? Vraiment ? Il ne faut pas passer par NSData ?

    http://developer.apple.com/mac/library/documentation/cocoa/conceptual/propertylists/Introduction/Introduction.html

    Et pour ceux que ça intéresse (ruby) :
    http://gist.github.com/303378

    Ceux qui préfèrent PHP :
    http://code.google.com/p/cfpropertylist/
  • AliGatorAliGator Membre, Modérateur
    01:43 modifié #6
    Heu ben si Alex, on peut lire des Plist, qu'ils soient binaires ou texte, avec NSDictionary et NSArray depuis des lustres.
    Tu dois même le faire sans le savoir.
    Quand tu initialises ton NSArray ou NSDict avec un plist, tu n'as pas besoin de savoir si ce dernier est binaire ou XML (ou même ASCII, ancien format encore supporté en lecture et encore utilisé par ex. pour les TextMacros), tu lui files le path et il le lit tout seul...
  • muqaddarmuqaddar Administrateur
    01:43 modifié #7
    dans 1276789535:

    Heu ben si Alex, on peut lire des Plist, qu'ils soient binaires ou texte, avec NSDictionary et NSArray depuis des lustres.
    Tu dois même le faire sans le savoir.
    Quand tu initialises ton NSArray ou NSDict avec un plist, tu n'as pas besoin de savoir si ce dernier est binaire ou XML (ou même ASCII, ancien format encore supporté en lecture et encore utilisé par ex. pour les TextMacros), tu lui files le path et il le lit tout seul...


    J'ai toujours lu des plists "normaux" donc je ne le savais pas.
    Du coup, ça devient très intéressant tout ça puisque ça marche nativement avec initWithContentsOfUrl.

    Je reste sceptique que ce soit plus light que JSON quand-même parce qu'au fond un PLIST est un XML "spécialisé".
    (je parle ici du poids et non du parsing)... mais si Apple le dit !
  • AliGatorAliGator Membre, Modérateur
    01:43 modifié #8
    Oui, c'est un XML spécialisé, mais avec des tags connus à  l'avance. Et sans attributs, que des tags. Du coup le parsing peut être bien plus optimisé. Je pense que ça vient de là .

    Pour les plist binaires, ils sont très utilisés sous OSX, tous les plist des préférences ou la plupart des plist aux divers endroits du système sont au format binaire depuis quelques versions majeures de OSX, justement car leur parsing est optimisé (normal, c'est déjà  parsé en fait, c'est juste du fread de données déjà  préparées).
    Et Property List Editor tout comme un initWithContentsOfFile peuvent les lire sans broncher, qu'ils soient binaires ou XML ou ASCII.

    Mais justement le seul moyen que je connais à  ce jour de générer un plist binaire, c'est justement en Cocoa également, en utilisant les méthodes appropriées (d'ailleurs je me demande si les méthodes "writeToFile:atomically:" de NSDictionary et NSArray ne créent pas des fichiers plist binaires également).
    A vrai dire, vu que j'ouvre les fichiers plist soit avec du code Cocoa, soit en double-cliquant dessus ce qui ouvre Property List Editor, soit avec "plutil -convert xml1" justement, bah je fais même pas gaffe si le plist est binaire ou XML tellement c'est transparent du coup : y'a qu'en l'ouvrant avec un éditeur de texte qu'on voit si c'est le cas ou pas.
    Note que si tu veux tester, et te faire un plist binaire, soit tu le fais par le code, mais sinon la commande "plutil" ou même Property List Editor te permettent de sauver au format de ton choix, XML ou binaire.

    Ce qui serait intéressant donc, c'est de savoir si c'est possible simplement, et comment (détails des specs du format binaire ?), de générer des plist binaires... depuis autre chose que MacOSX ou du code Cocoa. En particulier côté serveur. Y'a donc les libs Ruby que tu as citées, mais tout le monde n'utilise pas Ruby d'une part, et d'autre part ça m'intéresserait de connaà®tre le format et de savoir si c'est juste du retroengineering ou basé sur des specs officielles.
  • yoannyoann Membre
    01:43 modifié #9
    Pour ce qui est des plist binaire on les crée avec NSPropertyListSerialization qui fait partie de NSFoundation, donc présent dans PyObjC par exemple.

    Chose plus intéressante par contre, la gestion des plist fait partie de CoreFoundation, donc dispo sur Apple Open Source http://www.opensource.apple.com/source/CF/CF-550/
  • muqaddarmuqaddar Administrateur
    01:43 modifié #10
    Merci pour les explications Ali.
    C'est vraiment qu'ouvrant mes PLISTS avec Property List Eitor, je me suis jamais trop posé la question du format binaire ou XML.

    J'avais mis un lien vers un plugin PHP au dessus...
    J'ai installé le plugin Ruby, je vais tester ça.

    # CFPropertyList implementation
    # parser class to read, manipulate and write XML property list files (plist(5)) as defined by Apple


    Je vais vous faire un petit retour.
  • yoannyoann Membre
    01:43 modifié #11
    Pour info la session en question est la 117 qui n'est pas disponible en vidéo... Par contre les slides eux sont dispo si vous voulez regarder les graphes
  • muqaddarmuqaddar Administrateur
    01:43 modifié #12
    Bon, alors voilà , j'ai testé le plugin Ruby, et discuté un peu avec l'auteur.

    Côté serveur :

    &nbsp; def test&nbsp;  <br />&nbsp; &nbsp; @countries = Country.find :all<br />&nbsp; &nbsp; respond_to do |format|<br />&nbsp; &nbsp; &nbsp; format.plist { render :plist =&gt; @countries }<br />&nbsp; &nbsp; end<br />&nbsp; end
    


    Ce qui donne en téléchargement ceci (capture 1).

    Avez-vous remarqué dans le finder la preview (capture 2) où on voit le XML.

    En revanche, dans TextMate, mon éditeur de texte favori, le fichier est bien compressé... (capture 3)

    C'est beau la technologie et l'intégration Apple !

    Deci étant dit, je pense quand même me tourner vers JSON qui est plus universel que les PLIST (d'autant plus que je veux l'apprendre).

  • AliGatorAliGator Membre, Modérateur
    01:43 modifié #13
    Eh oui, le plugin QuickLook pour les .plist décode le contenu du plist en XML avant d'en afficher la preview, du coup tu n'y vois que du feu :-)
  • muqaddarmuqaddar Administrateur
    01:43 modifié #14
    En fait, le gros point noir avec cette solution, c'est que j'ai pas d'outil côté serveur pour décoder le PLIST... alors que j'en ai en JSON.
  • yoannyoann Membre
    01:43 modifié #15
    Effectivement coté Plist, la technique n'est valable que pour des clients iPhone, cela étant ce n'est pas très compliqué de faire deux sortie différente sur les webservices en fonction du client.

    De mon coté je suis entrain de tester la lib php et elle est bien sympa !

    Voici un extrait de code de test :

    PHP
    <br />&lt;?php<br />require_once(dirname(__FILE__).&#39;/cfpropertylist/CFPropertyList.php&#39;);<br />header(&quot;Content-Type: application/octet-stream; &quot;); <br />header(&quot;Content-Transfer-Encoding: binary&quot;);<br /><br />try {<br />	$bdd = new PDO(&#39;mysql:host=localhost;dbname=car&#39;, &#39;car&#39;, &#39;car&#39;);<br />} catch (Exception $e) {<br />&nbsp; &nbsp; &nbsp; &nbsp; die(&#39;Erreur : &#39; . $e-&gt;getMessage());<br />}<br /><br />if ($_GET&#91;&#39;info&#39;] == &quot;vendors&quot;) $cars = $bdd-&gt;query(&quot;SELECT * FROM&nbsp; `vendors`&quot;);<br />else if ($_GET&#91;&#39;info&#39;] == &quot;cars&quot;) $cars = $bdd-&gt;query(&quot;SELECT * FROM&nbsp; `cars`&quot;);<br /><br />if ($cars) {<br />	$cars-&gt;setFetchMode(PDO::FETCH_ASSOC);<br />	<br />	try {<br />		$plist = new CFPropertyList();<br />		$td = new CFTypeDetector();<br />	&nbsp; <br />		$plist-&gt;add($td-&gt;toCFType($cars-&gt;fetchAll()));<br />		print_r($plist-&gt;toBinary());<br />	}<br />	catch( PListException $e ) {<br />		echo &#39;Normal detection: &#39;, $e-&gt;getMessage(), &quot;&#092;n&quot;;<br />	}<br />}<br /><br />?&gt;<br />
    


    Avec ces 30 lignes de code j'ai une sortie Plist Binaire de ma base SQL... C'est un peut crade vu que je sort toute la table pour mes test mais il n'y a pas grand chose a rajouter pour avoir des limites...

    Et sur l'iPhone :
    <br />	self.cars = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:@&quot;http://serveur/index.php?info=cars&quot;]];<br />	self.vendors = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:@&quot;http://serveur/index.php?info=vendors&quot;]];<br />
    


    Pareil, ça mériterais plus de test et un mode asynchrone, mais j'aime bien :-)

    Seule chose, quelqu'un sait en quel encodage de caractère doivent être les plist binaire ? mes champs sont en UTF8 sur le serveur et pourtant mes accents saute dans le transfert
  • muqaddarmuqaddar Administrateur
    01:43 modifié #16
    Moi j'ai tout en UTF-8 et pas de soucis avec les accents.

    doc.encoding = LibXML::XML::Encoding::UTF_8
    
  • muqaddarmuqaddar Administrateur
    juin 2010 modifié #17
    Code serveur appelé :

    &nbsp; def test&nbsp;  <br />&nbsp; &nbsp; @aromas = Aroma.find :all<br />&nbsp; &nbsp; respond_to do |format|<br />&nbsp; &nbsp; &nbsp; format.plist { render :plist =&gt; @aromas, :plist_filename =&gt; &quot;alex.plist&quot; }<br />&nbsp; &nbsp; end<br />&nbsp; end
    


    code client Xcode :

    NSURL *url = [NSURL URLWithString:@&quot;http://0.0.0.0:3000/services/test&quot;];<br />	NSArray *aromas = [[NSArray alloc] initWithContentsOfURL:url];<br />	NSLog(@&quot;fr_name: %@&quot;, [[aromas objectAtIndex:1] objectForKey:@&quot;fr_name&quot;]);
    


    Oh le bel accent : ;)  :P

    Résultat :
    2010-06-18 19:13:21.218 vinocella[31202:207] fr_name: Clémentine
  • yoannyoann Membre
    01:43 modifié #18
    Tu peut essayer avec la version php ? Je pense que c'est leur code qui ne gère pas les accents.
  • muqaddarmuqaddar Administrateur
    01:43 modifié #19
    dans 1276882737:

    Tu peut essayer avec la version php ? Je pense que c'est leur code qui ne gère pas les accents.


    C'est possible. Pourtant le plugin que j'utilise s'appuie sur le cousin du plugin PHP que tu utilises, à  savoir cfpropertylist...

    Euh essayer en PHP ?  B) Tu m'as bien vu ?  8--) Le PHP je l'utilise que quand c'est obligatoire pour moi...
    Je ne regretterai jamais mon passage à  ruby et rails il y a 3 ans.

    T'es sûr que tout est en UFT-8 chez toi ? Serveur, site... ?
  • muqaddarmuqaddar Administrateur
    01:43 modifié #20
    J'ai regardé vite fait le plugin PHP et tout a l'air exporté en UTF-8...
  • yoannyoann Membre
    01:43 modifié #21
    dans 1276883917:

    C'est possible. Pourtant le plugin que j'utilise s'appuie sur le cousin du plugin PHP que tu utilises, à  savoir cfpropertylist...

    Euh essayer en PHP ?  B) Tu m'as bien vu ?  8--) Le PHP je l'utilise que quand c'est obligatoire pour moi...
    Je ne regretterai jamais mon passage à  ruby et rails il y a 3 ans.

    T'es sûr que tout est en UFT-8 chez toi ? Serveur, site... ?


    Perso je suis plus Python, je hais le PHP ^^ Mais malheureusement peut d'hébergeur mutualisé ont le ruby dispo...

    Pour ce qui est de l'UTF 8, je dirais que oui mais je ne suis pas expert en la matière, voici l'export SQL depuis PHPMyAdmin :

    <br />CREATE TABLE IF NOT EXISTS `cars` (<br />&nbsp; `id` int(10) unsigned NOT NULL auto_increment,<br />&nbsp; `title` text collate utf8_roman_ci NOT NULL,<br />&nbsp; `first_date` date NOT NULL,<br />&nbsp; `kilometers` int(10) unsigned NOT NULL,<br />&nbsp; `out_color` text collate utf8_roman_ci NOT NULL,<br />&nbsp; `in_color` text collate utf8_roman_ci NOT NULL,<br />&nbsp; `options` text collate utf8_roman_ci NOT NULL,<br />&nbsp; `price` float NOT NULL,<br />&nbsp; `vendor` int(11) NOT NULL,<br />&nbsp; PRIMARY KEY&nbsp; (`id`)<br />) ENGINE=MyISAM&nbsp; DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci AUTO_INCREMENT=3 ;<br />
    


    Je n'ai pas l'impression d'avoir oublié un truc... Au pire je vais tout recréer pour voir si j'ai pas loupé un truc.
  • muqaddarmuqaddar Administrateur
    01:43 modifié #22
    En fait, je suis chez un hébergeur américain, en mutualisé. Je paie 15$/mois, j'ai 8 sites en Ruby dessus, et la mise en place des sites est enfantine (pour du rails). En France, c'est le désert côté hébergement en effet...

    Pour ta base, oui elle semble être en UTF-8 mais le soucis vient p-e de pas de là .

    Par exemple, bien qu'ayant une base en UTF-8, j'étais obligé de forcer le fonctionnement de la base en UTF-8 il y a encore 2 ans :

    &nbsp; # Use this method as a before_filter. It&#39;ll make sure database will welcome utf-8 encoded input.<br />&nbsp; def configure_database_charset<br />&nbsp; &nbsp; suppress(ActiveRecord::StatementInvalid) do<br />&nbsp; &nbsp; &nbsp; ActiveRecord::Base.connection.execute &#39;SET NAMES UTF8&#39;<br />&nbsp; &nbsp; end<br />&nbsp; end&nbsp;
    


    Aujourd'hui, c'est fait par défaut dans Rails.


    Peux-tu mettre à  quoi ressemble ton Plist ?
  • yoannyoann Membre
    01:43 modifié #23
    Ok je viens de faire des test avec la sortie en XML (plus simple pour deboguer avec Safari) et effectivement il faut que je règle l'encodage en ISO Latin 1 pour qu'il réussisse à  afficher les données...

    Mais du coup je ne comprend pas d'où viens le problème la, à  moins qu'il y a une options spéciale avec PHP pour lui dire de bosser en UTF-8 ?
  • yoannyoann Membre
    01:43 modifié #24
    Ok merci Alex pour m'avoir mis sur la voie, il faut effectivement faire comprendre à  PHP qu'on travail avec l'UTF8 lors de la connexion à  la base MySQL :

    $bdd = new PDO(&#39;mysql:host=localhost;dbname=bm&#39;, &#39;bm&#39;, &#39;bm&#39;, array(PDO::MYSQL_ATTR_INIT_COMMAND =&gt; &quot;SET NAMES utf8&quot;));
    
  • muqaddarmuqaddar Administrateur
    01:43 modifié #25
    Super que tu aies trouvé. :-)

    De mon côté, à  force d'aller-retours avec l'auteur du plugin Rails, on a ajouté :
    - la création d'un dictionnaire arbitraire possible (sans données provenant de la base)
    - la possibilité de donner un nom au fichier plist sortant
    - et bientôt la possibilité de traiter un plist entrant pour le convertir en array ruby ou hash...
  • yoannyoann Membre
    01:43 modifié #26
    Bon bah franchement je suis bien content de ce petit test, même si j'ai du faire du PHP pour cela, ça fait gagner un temps considérable !

    Je me suis rajouter une petite NSOperation fait pour le chargement sur URL de NSArray/NSDictionary et roulez !

    Je pense qu'aujourd'hui, autant que possible je vais travailler avec les plist binaires, d'autant que ce n'est que très peut de code a rajouter sur les webservices
  • muqaddarmuqaddar Administrateur
    01:43 modifié #27
    Bon, nous, avec Jeena, on a continué à  avancer.
    On peut donc maintenant envoyer un PLIST binaire en POST et récupérer les données en PARAMS côté serveur, parsing automatique.  <3 <br />
    Ainsi, en cocoa :


    NSMutableDictionary *dict = [NSMutableDictionary dictionary];<br />	[dict setObject:@&quot;toto&quot; forKey:@&quot;stringKey&quot;];<br />	NSArray *array = [NSArray arrayWithObjects:@&quot;value1&quot;, @&quot;value2&quot;, nil];<br />	[dict setObject:array forKey:@&quot;arrayKey&quot;];	<br /><br />	NSURL *url = [NSURL URLWithString:@&quot;http://0.0.0.0:3000/services/test&quot;];<br />	ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];<br />	[request addRequestHeader:@&quot;Content-Type&quot; value:@&quot;application/plist&quot;];<br /><br />	NSData *data = [NSPropertyListSerialization dataFromPropertyList:dict format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];<br />	[request appendPostData:data];<br /><br />	[request startAsynchronous];
    


    et côté serveur, voilà  ce qui est décortiqué :

    Processing ServicesController#test (for 127.0.0.1 at 2010-06-20 20:29:40) [POST]<br />&nbsp; Session ID: 7fb2a3d5647a84a47ae111d5459adede<br />&nbsp; Parameters: { &quot;controller&quot;=&gt;&quot;services&quot;, &quot;action&quot;=&gt;&quot;test&quot;,&nbsp; &quot;stringKey&quot;=&gt;&quot;toto&quot;,&nbsp; &quot;arrayKey&quot;=&gt;[&quot;value1&quot;, &quot;value2&quot;]}
    



Connectez-vous ou Inscrivez-vous pour répondre.