Receptes de cuina amb Recipe XML

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

RecipeBook XML és un llenguatge de marques que s'utilitza per fer receptes i llibre de cuina. És simple i fàcil d'utilitzar i aprendre, i com tots els llenguatges XML té enormes possibilitats. Un cop s'ha escrit una recepta amb RecipeBook XML, es pot formatar amb diferents formats (HTML, PDF, Rich Text,...), com ja vas veure l'any passat a l'assignatura de XML.

Referències

La definició del llenguatge recipeXML estava a http://www.happy-monkey.net/recipebook/, però malauradament aquest enllaç està trencat. No passa res, doncs els fitxers XML d'exemple de què disposem s'expliquen per ells mateixos. Pots descarregar-te dos fitxers d'exemple:

Desenvolupament

Primera prova

El fitxer index1.html carrega en una select box 2 fitxers XML (fitxers d'exemple que pots descarregar de l'enllaç). Mitjançant la tècnica asíncrona d'AJAX mostra els ingredients per pantalla, en la capa corresponent. Aquest codi és bàsicament similar al que s'ha vist a classe en l'exemple de tutoria. fitxer index1.html:

<html>
<head>
<title>Receptes AJAX</title>
<script>
function loadXMLDoc(url)
{

var xmlhttp;
var txt,x,xx,i;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    txt="<h2>Ingredients</h2>";
    txt = txt + "<ul>";
		x=xmlhttp.responseXML.documentElement.getElementsByTagName("fooditem");
		for (i=0;i<x.length;i++) {
			txt = txt + '<li>' + x[i].firstChild.nodeValue + '</li>';
		}
    txt = txt + "</ul>";
    document.getElementById('info').innerHTML=txt;
    }
  }
xmlhttp.open("GET",url,true);
xmlhttp.send();

}
</script>
</head>
<body>
<h1>Receptes</h1>
<div id="formulari">
<form name="frm_receptes" id="formu" action="#">
	<select name="recipes" onchange="loadXMLDoc(this.value)">
	<option value="recipes/bean-and-ham.xml">bean and ham</option>
	<option value="recipes/corn-chowder.xml">corn chowder</option>
	</select><br />
</form>
</div>
<div id="info">
</div>
</body>
</html>

Obtenim:

    dry navy beans
    medium onion
    garlic
    celery
    carrots
    plum (roma) tomatoes
    cooked ham scraps
    water
    ham bone
    Salt
    pepper

Fixa't bé que estem parsejant el fitxer XML en el cantó del client (Javascript). L'objecte xmlhttp.responseXML conté tot els fitxer complet, i amb Javascript filtrem la informació que ens interessa, en aquest cas els ingredients. Això seria ineficient si el fitxer XML fos molt gros (posem per cas 500K) i només ens interessa una petita part de la informació.

L'alternativa eś que sigui PHP, en el cantó del servidor, qui parsegi el fitxer XML i només envïi al client la informació que interessa, en aquest cas els ingredients. Aquesta manera de fer està discutida en el següent enllaç:

Segona prova

En la primera prova hem recuperat els valors dels fooditem. Però interessa més recuperar la informació dels ingredients, que està format per: fooditem, quantity, unit. Ara la navegació pel document XML és més complicada. Navegarem pels diferents ingredients utilitzant:

getElementsByTagName("ingredient")

i, dins de cada ingredient buscarem els seus childNodes. Utilitzarem la propietat nodeName per buscar les etiquetes quantity, unit i fooditem. I finalment accedirem al valor de text mitjançant childNodes[0].nodeValue. És bastant embolic però funciona bé. Utilitzem variables per formatar la sortida.

fitxer index2.html

<html>
<head>
<title>Receptes AJAX</title>
<script>
function loadXMLDoc(url)
{

var xmlhttp;
var txt,x,xx,i;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    txt="<h2>Ingredients</h2>";
    txt = txt + "<ul>";
	 txt_ingredient = "";
	 txt_quantity = "";
	 txt_unit = "";
	 txt_fooditem = "";
		ingredients=xmlhttp.responseXML.documentElement.getElementsByTagName("ingredient");
		for (i=0;i<ingredients.length;i++) {
			//alert(ingredients[i].innerHTML);			
			for (k=0;k<ingredients[i].childNodes.length;k++) {			
				//alert(ingredients[i].childNodes[k].nodeName);
				if (ingredients[i].childNodes[k].nodeName == "quantity") txt_quantity = ingredients[i].childNodes[k].childNodes[0].nodeValue;
				if (ingredients[i].childNodes[k].nodeName == "unit") txt_unit = ingredients[i].childNodes[k].childNodes[0].nodeValue;
				if (ingredients[i].childNodes[k].nodeName == "fooditem") txt_fooditem = ingredients[i].childNodes[k].childNodes[0].nodeValue;
			}
			txt_ingredient = "<li>" + txt_fooditem + " (" + txt_quantity + " " + txt_unit + ")</li>"
			txt = txt + txt_ingredient;
		}
    txt = txt + "</ul>";
    document.getElementById('info').innerHTML=txt;
    }
  }
xmlhttp.open("GET",url,true);
xmlhttp.send();

}
</script>
</head>
<body>
<h1>Receptes</h1>
<div id="formulari">
<form name="frm_receptes" id="formu" action="#">
	<select name="recipes" onchange="loadXMLDoc(this.value)">
	<option value="">Escull una recepta</option>
	<option value="recipes/bean-and-ham.xml">bean and ham</option>
	<option value="recipes/corn-chowder.xml">corn chowder</option>
	</select><br />
</form>
</div>
<div id="info">
</div>
</body>
</html>

Obtenim:

    butter (2 Tbsp.)
    medium onion (1 Tbsp.)
    garlic (2 cloves)
    celery (2 ribs)
    red pepper (1 ribs)
    corn (4 ears)
    flour (2 Tbsp.)
    chicken broth (2 C.)
    whole milk (2 C.)
    medium red potatoes (3 C.)
    Salt and pepper (3 C.)

Feina per l'alumne

A partir d'aquí hem de fer una aplicació més interessant. S'ha de mostrar la resta d'informació que hi ha en el fitxer XML: la capçalera de la recepta (títol, autor), ingredients, mode de preparació, com es serveix... i la foto.

Incloure una foto és una opció que ha sorgit de la discussió que s'ha fet a classe. L'atribut foto ha d'anar dins la informació relativa a la recepta (a dalt de tot, allà on hi ha el títol i l'autor). La idea dels fitxers XML és que són autocontinguts. Per exemple, pots enviar per mail un fitxer xml a un col.lega. El problema és que si hi ha referència a unes fotos, necessitem que aquestes fotos tinguin una url absoluta (en cas contrari, quan envïis una recepta per mail, a més del fitxer també hauràs d'incloure la foto).

No cal incorporar en el llenguatge Recipe XML la informació de la imatge. N'hi ha prou en obligar que la imatge (.png) tingui el mateix nom que el fitxer xml.

Recordatori:

Per exemple, si tenim el fitxer patates_fregides.xml, la imatge corresponent serà patates_fregides.png.

La nostra aplicació completa inclou aspectes de disseny i aspectes de usabilitat i funcionalitat, tal com s'ha discutit a classe. Es fa la proposta següent (però l'alumne podrà fer altres proves i millores).

NOTA. Hem fet la prova d'accedir a fitxers XML remots, com ara

i no hem pogut fer-ho. De fet, plantejat així no es pot fer, però hi ha una solució alternativa que mirarem d'implementar.

Com diu en l'anterior enllaç:

You can't send an AJAX request to another server, see http://en.wikipedia.org/wiki/Same_origin_policy A workaround is to use JSONP: http://en.wikipedia.org/wiki/JSONP

SOLUCIÓ JSONP: JSONP:_JSON_with_Padding#RecipeXML_i_JSONP

Repositori de les receptes dels alumnes

La url d'on pots agafar totes les receptes i les imatges és (curs 19-20):

(pots consultar les receptes dels anys anteriors)


Cada alumne ha d'enviar obligatòriament dues receptes (i les dues fotos), a jquintana@jaumebalmes.net. Això és NOTA de classe. Termini màxim: 03/02/2020.

A data 03/02/2020, el repositori de receptes és:

<select id="recipes" name="recipes" onchange="loadXMLDoc(this.value)">
     <option value=""></option>
     <option value="arros_calamars_llauna.xml">Arròs de calamars a la llauna</option>
     <option value="arroz_con_leche.xml">Arroz con leche</option>
     <option value="bean-and-ham.xml">Bean and Ham</option>
     <option value="bizcocho.xml">Bizcocho</option>
     <option value="bizcocho_micro.xml">Bizcocho micro</option>
     <option value="bizcocho_platano.xml">Bizcocho de plátano</option>
     <option value="canelones.xml">Canelones</option>
     <option value="carne_mechada.xml">Carne mechada</option>
     <option value="cordero_al_horno.xml">Cordero al horno</option>
     <option value="corn-chowder.xml">Corn Chowder</option>
     <option value="crema_de_castanyes.xml">Crema de castanyes</option>
     <option value="flao.xml">Flaó</option>
     <option value="focaccia-verduras.xml">Focaccia de verduras</option>
     <option value="lubina-a-la-sal.xml">Lubina a la sal</option>
     <option value="macarrones_con_queso.xml">Macarrones con queso</option>
     <option value="macedonia.xml">Macedònia</option>
     <option value="mousse-de-chocolate.xml">Mousse de chocolate</option>
     <option value="natillas_caseras.xml">Natillas caseras</option>
     <option value="oliaigua.xml">Oliaigua</option>
     <option value="paella-marisco.xml">Paella de marisco</option>
     <option value="peus_porc_ceps.xml">Peus de porc amb ceps</option>
     <option value="pollo-a-la-naranja.xml">Pollo a la naranja</option>
     <option value="sofrit_pages.xml">Sofrit de pagès</option>
     <option value="Spaghetti_al_pesto_de_albahaca_y_almendra.xml">Spaghetti al pesto de albahaca</option>
     <option value="Spaghetti_con_salsa_de_pimientos_del_piquillo.xml">Spaghetti 
      con salsa de pimientos</option>
     <option value="spaguetti-carbonara.xml">Spaguetti a la Carbonara</option>
     <option value="tequeños.xml">Tequeños</option>
     <option value="torrijas_de_leche.xml">Torrijas de leche</option>
     <option value="tortilla_con_cebolla.xml">Tortilla con cebolla</option>
</select>

Disseny

Hem de definir una estructura, una plantilla, on mostrar tota la informació desitjada. Evidentment, ho farem amb capes div. Una proposta és:

--------------  -----------------
| select box |  |   Títol       |
--------------  -----------------
-------------   ----------------
|            |  |    Gènere     |
|            |  |---------------|
|ingredients |  | foto          |
|            |  |               |
-------------   -----------------
---------------------------------
|                               |
|    preparació                 |
|                               |
---------------------------------
---------------------------------
|    servir                     |
---------------------------------

però l'alumne la pot canviar segons el seu criteri.

Funcionalitat

Tan important com el disseny és la manera com se'ns mostra la informació (cerquem que sigui una pàgina dinàmica i divertida). Aquí, la proposta que s'ha discutit és que, amb un delay de 5 segons, es vagin carregant les diferents zones de la pàgina: primer el títol, els ingredients, la foto, la preparació, el mode de servir. per tant, seran diferents crides asíncrones al servidor per demanar la informació amb què hem de carregar cadascuna de les pàgines.

Una altra opció és que per mostrar la informació s'una capa s'ha de fer click sobre la capa. Així doncs, només es mostra la informació que volem llegir.

Són propostes, tu pots fer la teva proposta.

Fés la teva recepta

Finalment has d'incorporar a la teva aplicació un parell de receptes de collita pròpia. Si no ets afeccionat a la cuina pots agafar idees d'algun blog de cuina, per exemple una recepta de les Cuineres de Sils:

Hauràs de buscar una foto real de les teves receptes (tamany 200x200px), i ficar-la a la carpeta recipes/img

Solució final

Se t'entrega una solució ben maquetada i funcionant. Contingut de les carpetes:

Millores: tag equipment! (febrer 2020)

<preparation>Per fer aquesta recepte necessitem un <equipment>forn</equipment>, i també haurem de tenir a la vora una <equipment>màquina d'amassar pa</equipment>...</preparation>

L'etiqueta <equipment> dins de l'etiqueta <preparation> fa que no sigui tan fàcil maquetar el text que hi ha dins de <preparation>. La solució que s'ha trobat és la següent:

  prep= xmlDoc.getElementsByTagName("preparation");

  if (prep.length > 0) {
    //preparacion = prep[0].firstChild.nodeValue; //recordar que pot haver-hi <equipment> fent la pua!!
    //alert(prep[0].childNodes.length);
    let cad_preparacion ="";
    for (let i=0; i<prep[0].childNodes.length;i++) {
      //alert(prep[0].childNodes[i].nodeType);
      if (prep[0].childNodes[i].nodeType==1) { //node Element, que és el <equipment>
        cad_preparacion += prep[0].childNodes[i].firstChild.nodeValue
      } else {
        cad_preparacion += prep[0].childNodes[i].nodeValue;
      }
    }

    //cad_preparacion = cad_preparacion.replace("\n", "<br /><br />"); //només reemplaça el primer valor
    cad_preparacion = cad_preparacion.replace(/\n/gi, "<br /><br />");

A més a més, hem reemplaçat els retorns de carro (\n) per preservar els salts de línia.

Entrega

Els alumnes entregaran al Schoology tots els fitxers generats (fitxers html). S'empaquetaran tots aquests fitxers i es pujaran al Schoology dins del termini d'entrega de la pràctica.

Recorda la normativa per entregar les pràctiques al Schoology: ASIX-M10-UF2#Normativa_d.27entrega_de_les_pr.C3.A0ctiques_al_Schoology


creat per Joan Quintana Compte, febrer 2019

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines