diff options
Diffstat (limited to 'src/importers/recipemlimporter.cpp')
-rw-r--r-- | src/importers/recipemlimporter.cpp | 376 |
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; +} |