summaryrefslogtreecommitdiffstats
path: root/src/importers/recipemlimporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/importers/recipemlimporter.cpp')
-rw-r--r--src/importers/recipemlimporter.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/importers/recipemlimporter.cpp b/src/importers/recipemlimporter.cpp
new file mode 100644
index 0000000..8866648
--- /dev/null
+++ b/src/importers/recipemlimporter.cpp
@@ -0,0 +1,376 @@
+/***************************************************************************
+* Copyright (C) 2003 by *
+* Richard L�rk�ng *
+* *
+* Copyright (C) 2003-2005 by *
+* Jason Kivlighn ([email protected]) *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+***************************************************************************/
+
+#include "recipemlimporter.h"
+
+#include <tqfile.h>
+#include <tqdatetime.h>
+
+#include <tdelocale.h>
+#include <kdebug.h>
+
+#include "datablocks/recipe.h"
+#include "datablocks/mixednumber.h"
+
+RecipeMLImporter::RecipeMLImporter() : BaseImporter()
+{}
+
+void RecipeMLImporter::parseFile( const TQString& file )
+{
+ TQFile input( file );
+ if ( input.open( IO_ReadOnly ) ) {
+ TQDomDocument doc;
+ TQString error;
+ int line;
+ int column;
+ if ( !doc.setContent( &input, &error, &line, &column ) ) {
+ setErrorMsg( TQString( i18n( "\"%1\" at line %2, column %3. This may not be a RecipeML file." ) ).arg( error ).arg( line ).arg( column ) );
+ return ;
+ }
+
+ TQDomElement recipeml = doc.documentElement();
+
+ if ( recipeml.tagName() != "recipeml" ) {
+ setErrorMsg( i18n( "This file does not appear to be a valid RecipeML archive." ) );
+ return ;
+ }
+
+ TQDomNodeList l = recipeml.childNodes();
+
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "meta" )
+ continue;
+ else if ( tagName == "recipe" )
+ readRecipemlRecipe( el );
+ else if ( tagName == "menu" )
+ readRecipemlMenu( el );
+ else
+ kdDebug() << "Unknown tag within <recipeml>: " << tagName << endl;
+ }
+ }
+ else
+ setErrorMsg( i18n( "Unable to open file." ) );
+}
+
+RecipeMLImporter::~RecipeMLImporter()
+{}
+
+void RecipeMLImporter::readRecipemlRecipe( const TQDomElement& recipe_element )
+{
+ recipe.empty();
+
+ TQDomNodeList l = recipe_element.childNodes();
+
+ for ( unsigned i = 0; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "head" )
+ readRecipemlHead( el );
+ else if ( tagName == "ingredients" )
+ readRecipemlIngs( el );
+ else if ( tagName == "directions" )
+ readRecipemlDirections( el );
+ else if ( tagName == "description" ) {} //TODO: what do we do with this?
+ else if ( tagName == "equipment" ) {} //TODO: what do we do with this?
+ else if ( tagName == "nutrition" ) {} //TODO: what do we do with this?
+ else if ( tagName == "diet-exchanges" ) {} //TODO: what do we do with this?
+ else
+ kdDebug() << "Unknown tag within <recipe>: " << el.tagName() << endl;
+ }
+
+ add
+ ( recipe );
+}
+
+void RecipeMLImporter::readRecipemlHead( const TQDomElement& head )
+{
+ TQDomNodeList l = head.childNodes();
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "title" )
+ recipe.title = el.text().stripWhiteSpace();
+ else if ( tagName == "subtitle" )
+ recipe.title += ": " + el.text().stripWhiteSpace();
+ else if ( tagName == "version" ) {} //TODO: what do we do with this?
+ else if ( tagName == "source" )
+ readRecipemlSrcItems( el );
+ else if ( tagName == "categories" ) {
+ TQDomNodeList categories = el.childNodes();
+ for ( unsigned j = 0; j < categories.count(); j++ ) {
+ TQDomElement c = categories.item( j ).toElement();
+ if ( c.tagName() == "cat" ) {
+ recipe.categoryList.append( Element( c.text() ) );
+ }
+ }
+ }
+ else if ( tagName == "description" )
+ recipe.instructions += "\n\nDescription: " + el.text().stripWhiteSpace();
+ else if ( tagName == "preptime" )
+ readRecipemlPreptime( el );
+ else if ( tagName == "yield" ) {
+ TQDomNodeList yieldChildren = el.childNodes();
+ for ( unsigned j = 0; j < yieldChildren.count(); j++ ) {
+ TQDomElement y = yieldChildren.item( j ).toElement();
+ TQString tagName = y.tagName();
+ if ( tagName == "range" )
+ readRecipemlRange( y, recipe.yield.amount, recipe.yield.amount_offset );
+ else if ( tagName == "unit" )
+ recipe.yield.type = y.text();
+ else
+ kdDebug() << "Unknown tag within <yield>: " << y.tagName() << endl;
+ }
+ }
+ else
+ kdDebug() << "Unknown tag within <head>: " << el.tagName() << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlIngs( const TQDomElement& ings )
+{
+ TQDomNodeList l = ings.childNodes();
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "ing" )
+ readRecipemlIng( el );
+ else if ( tagName == "ing-div" ) //NOTE: this can have the "type" attribute
+ {
+ TQString header;
+ TQDomNodeList ingDiv = el.childNodes();
+ for ( unsigned j = 0; j < ingDiv.count(); j++ )
+ {
+ TQDomElement cEl = ingDiv.item( j ).toElement();
+ if ( cEl.tagName() == "title" )
+ header = cEl.text().stripWhiteSpace();
+ else if ( cEl.tagName() == "description" ) {} //TODO: what do we do with this?
+ else if ( cEl.tagName() == "ing" )
+ readRecipemlIng( cEl, 0, header );
+ else if ( tagName == "note" ) {} //TODO: what do we do with this?
+ else
+ kdDebug() << "Unknown tag within <ing-div>: " << cEl.tagName() << endl;
+ }
+ }
+ else if ( tagName == "note" ) {} //TODO: what do we do with this?
+ else
+ kdDebug() << "Unknown tag within <ingredients>: " << el.tagName() << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlIng( const TQDomElement& ing, Ingredient *ing_parent, const TQString &header )
+{
+ Ingredient new_ing;
+
+ TQDomNodeList ingChilds = ing.childNodes();
+
+ TQString name, unit, size, prep_method;
+ Ingredient quantity;
+ quantity.amount = 1;// default quantity assumed by RecipeML DTD
+
+ for ( unsigned j = 0; j < ingChilds.count(); j++ ) {
+ TQDomElement ingChild = ingChilds.item( j ).toElement();
+ TQString tagName = ingChild.tagName();
+
+ if ( tagName == "amt" ) {
+ TQDomNodeList amtChilds = ingChild.childNodes();
+
+ for ( unsigned k = 0; k < amtChilds.count(); k++ ) {
+ TQDomElement amtChild = amtChilds.item( k ).toElement();
+
+ if ( amtChild.tagName() == "qty" )
+ readRecipemlTQty( amtChild, quantity );
+ else if ( amtChild.tagName() == "size" )
+ size = amtChild.text().stripWhiteSpace();
+ else if ( amtChild.tagName() == "unit" )
+ unit = amtChild.text().stripWhiteSpace();
+ else
+ kdDebug() << "Unknown tag within <amt>: " << amtChild.tagName() << endl;
+ }
+ }
+ else if ( tagName == "item" ) {
+ name = ingChild.text().stripWhiteSpace();
+ if ( ing.attribute( "optional", "no" ) == "yes" )
+ prep_method = "(optional)";
+ }
+ else if ( tagName == "prep" ) { //FIXME: this overwrite the optional attribute
+ prep_method = ingChild.text().stripWhiteSpace();
+ }
+ else if ( tagName == "alt-ing" )
+ readRecipemlIng( ingChild, &new_ing, header );
+ else
+ kdDebug() << "Unknown tag within <ing>: " << ingChild.tagName() << endl;
+ }
+
+ if ( !size.isEmpty() )
+ unit.prepend( size + " " );
+
+ new_ing.name = name;
+ new_ing.units = Unit( unit, quantity.amount+quantity.amount_offset );
+ new_ing.amount = quantity.amount;
+ new_ing.amount_offset = quantity.amount_offset;
+ new_ing.group = header;
+ new_ing.prepMethodList = ElementList::split(",",prep_method);
+
+ if ( !ing_parent )
+ recipe.ingList.append(new_ing);
+ else
+ ing_parent->substitutes.append( new_ing );
+}
+
+void RecipeMLImporter::readRecipemlDirections( const TQDomElement& dirs )
+{
+ TQDomNodeList l = dirs.childNodes();
+
+ TQStringList directions;
+
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+
+ if ( el.tagName() == "step" )
+ directions.append( el.text().stripWhiteSpace() );
+ else
+ kdDebug() << "Unknown tag within <directions>: " << el.tagName() << endl;
+ }
+
+ TQString directionsText;
+
+ if ( directions.count() > 1 ) {
+ for ( unsigned i = 1; i <= directions.count(); i++ ) {
+ if ( i != 1 ) {
+ directionsText += "\n\n";
+ }
+
+ TQString sWith = TQString( "%1. " ).arg( i );
+ TQString text = directions[ i - 1 ];
+ if ( !text.stripWhiteSpace().startsWith( sWith ) )
+ directionsText += sWith;
+ directionsText += text;
+ }
+ }
+ else
+ directionsText = directions[ 0 ];
+
+ recipe.instructions = directionsText;
+}
+
+void RecipeMLImporter::readRecipemlMenu( const TQDomElement& menu_el )
+{
+ TQDomNodeList l = menu_el.childNodes();
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "head" )
+ readRecipemlHead( el );
+ else if ( tagName == "description" ) {} //TODO: what do we do with this?
+ else if ( tagName == "recipe" )
+ readRecipemlRecipe( el );
+ else
+ kdDebug() << "Unknown tag within <menu>: " << tagName << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlSrcItems( const TQDomElement& sources )
+{
+ TQDomNodeList l = sources.childNodes();
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement srcitem = l.item( i ).toElement();
+ TQString tagName = srcitem.tagName();
+
+ if ( tagName == "srcitem" )
+ recipe.authorList.append( Element( srcitem.text().stripWhiteSpace() ) );
+ else
+ kdDebug() << "Unknown tag within <source>: " << tagName << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlPreptime( const TQDomElement &preptime )
+{
+ TQDomNodeList l = preptime.childNodes();
+ for ( unsigned i = 0 ; i < l.count(); i++ ) {
+ TQDomElement el = l.item( i ).toElement();
+ TQString tagName = el.tagName();
+
+ if ( tagName == "time" ) {
+ int qty = 0;
+ TQString timeunit;
+
+ TQDomNodeList time_l = el.childNodes();
+ for ( unsigned i = 0 ; i < time_l.count(); i++ ) {
+ TQDomElement time_el = time_l.item( i ).toElement();
+ TQString time_tagName = time_el.tagName();
+
+ if ( time_tagName == "qty" )
+ qty = time_el.text().toInt();
+ else if ( time_tagName == "timeunit" )
+ timeunit = time_el.text();
+ else
+ kdDebug() << "Unknown tag within <time>: " << time_tagName << endl;
+ }
+
+ int minutes = 0;
+ int hours = 0;
+ if ( timeunit == "minutes" )
+ minutes = qty;
+ else if ( timeunit == "hours" )
+ hours = qty;
+ else
+ kdDebug() << "Unknown timeunit: " << timeunit << endl;
+
+ recipe.prepTime = TQTime( hours + minutes / 60, minutes % 60 );
+ }
+ else
+ kdDebug() << "Unknown tag within <preptime>: " << tagName << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlTQty( const TQDomElement &qty, Ingredient &ing )
+{
+ TQDomNodeList qtyChilds = qty.childNodes();
+
+ for ( unsigned i = 0; i < qtyChilds.count(); i++ ) {
+ TQDomElement qtyChild = qtyChilds.item( i ).toElement();
+ TQString tagName = qtyChild.tagName();
+ if ( tagName == "range" )
+ readRecipemlRange( qtyChild, ing.amount, ing.amount_offset );
+ else if ( tagName.isEmpty() )
+ ing.amount = MixedNumber::fromString( qty.text() ).toDouble();
+ else
+ kdDebug() << "Unknown tag within <qty>: " << tagName << endl;
+ }
+}
+
+void RecipeMLImporter::readRecipemlRange( const TQDomElement& range, double &amount, double &amount_offset )
+{
+ TQDomNodeList rangeChilds = range.childNodes();
+ double q1 = 1, q2 = 0; // default quantity assumed by RecipeML DTD
+ for ( unsigned j = 0; j < rangeChilds.count(); j++ ) {
+ TQDomElement rangeChild = rangeChilds.item( j ).toElement();
+ TQString subTagName = rangeChild.tagName();
+ if ( subTagName == "q1" )
+ q1 = MixedNumber::fromString( rangeChild.text() ).toDouble();
+ else if ( subTagName == "q2" )
+ q2 = MixedNumber::fromString( rangeChild.text() ).toDouble();
+ else
+ kdDebug() << "Unknown tag within <range>: " << subTagName << endl;
+ }
+
+ amount = q1;
+ amount_offset = q2-q1;
+}