added extractors HRecipe and HItem
Project: http://git-wip-us.apache.org/repos/asf/any23/repo Commit: http://git-wip-us.apache.org/repos/asf/any23/commit/1616c17c Tree: http://git-wip-us.apache.org/repos/asf/any23/tree/1616c17c Diff: http://git-wip-us.apache.org/repos/asf/any23/diff/1616c17c Branch: refs/heads/master Commit: 1616c17cb6497bcdf7947ee1048027f1b6d83a9f Parents: ff81602 Author: Nisala Nirmana <[email protected]> Authored: Mon Jul 6 01:50:42 2015 +0530 Committer: Nisala Nirmana <[email protected]> Committed: Mon Jul 6 01:50:42 2015 +0530 ---------------------------------------------------------------------- .../main/java/org/apache/any23/vocab/HItem.java | 30 +++ .../html/microformats2/HItemExtractor.java | 85 +++++++++ .../microformats2/HItemExtractorFactory.java | 40 ++++ .../html/microformats2/HRecipeExtractor.java | 189 +++++++++++++++++++ .../microformats2/HRecipeExtractorFactory.java | 57 ++++++ .../html/microformats2/HItemExtractorTest.java | 38 ++++ .../microformats2/HRecipeExtractorTest.java | 39 ++++ .../microformats2/h-item/h-item-test.html | 27 +++ .../microformats2/h-recipe/h-recipe-test.html | 71 +++++++ 9 files changed, 576 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/api/src/main/java/org/apache/any23/vocab/HItem.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/any23/vocab/HItem.java b/api/src/main/java/org/apache/any23/vocab/HItem.java new file mode 100644 index 0000000..db54e65 --- /dev/null +++ b/api/src/main/java/org/apache/any23/vocab/HItem.java @@ -0,0 +1,30 @@ +package org.apache.any23.vocab; + +import org.openrdf.model.URI; + +/** + * Vocabulary to map the <a href="http://microformats.org/wiki/hitem">h-item</a> microformat. + * + * @author Nisala Nirmana + */ +public class HItem extends Vocabulary { + + public static final String NS = SINDICE.NS + "hitem/"; + + private static HItem instance; + + public static HItem getInstance() { + if(instance == null) { + instance = new HItem(); + } + return instance; + } + + public URI Item = createClass(NS, "Item"); + public URI name = createProperty(NS, "name"); + public URI url = createProperty(NS, "url"); + public URI photo = createProperty(NS, "photo"); + private HItem() { + super(NS); + } +} http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractor.java b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractor.java new file mode 100644 index 0000000..19ed757 --- /dev/null +++ b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractor.java @@ -0,0 +1,85 @@ +package org.apache.any23.extractor.html.microformats2; + +import org.apache.any23.extractor.ExtractionException; +import org.apache.any23.extractor.ExtractionResult; +import org.apache.any23.extractor.ExtractorDescription; +import org.apache.any23.extractor.TagSoupExtractionResult; +import org.apache.any23.vocab.HItem; +import org.openrdf.model.BNode; +import org.openrdf.model.URI; +import org.openrdf.model.vocabulary.RDF; +import org.w3c.dom.Node; +import org.apache.any23.extractor.html.EntityBasedMicroformatExtractor; +import org.apache.any23.extractor.html.HTMLDocument; + +/** + * Extractor for the <a href="http://microformats.org/wiki/h-item">h-item</a> + * microformat. + * + * @author Nisala Nirmana + */ +public class HItemExtractor extends EntityBasedMicroformatExtractor { + + private static final HItem vHITEM = HItem.getInstance(); + + private static final String[] itemFields = { + "name", + "url", + "photo" + }; + + @Override + public ExtractorDescription getDescription() { + return HItemExtractorFactory.getDescriptionInstance(); + } + + protected String getBaseClassName() { + return Microformats2Prefixes.CLASS_PREFIX+"item"; + } + + @Override + protected void resetExtractor() { + // Empty. + } + + protected boolean extractEntity(Node node, ExtractionResult out) throws ExtractionException{ + if (null == node) return false; + final HTMLDocument document = new HTMLDocument(node); + BNode item = getBlankNodeFor(node); + out.writeTriple(item, RDF.TYPE, vHITEM.Item); + final String extractorName = getDescription().getExtractorName(); + addName(document,item); + addPhotos(document,item); + addUrls(document,item); + final TagSoupExtractionResult tser = (TagSoupExtractionResult) getCurrentExtractionResult(); + tser.addResourceRoot(document.getPathToLocalRoot(), item, this.getClass()); + return true; + } + + private void mapFieldWithProperty(HTMLDocument fragment, BNode item, String fieldClass, URI property) { + HTMLDocument.TextField title = fragment.getSingularTextField(fieldClass); + conditionallyAddStringProperty( + title.source(),item, property, title.value() + ); + } + + private void addName(HTMLDocument fragment, BNode item) { + mapFieldWithProperty(fragment, item, Microformats2Prefixes.PROPERTY_PREFIX+itemFields[0], vHITEM.name); + } + + private void addPhotos(HTMLDocument fragment, BNode item) throws ExtractionException { + final HTMLDocument.TextField[] photos = fragment.getPluralUrlField + (Microformats2Prefixes.URL_PROPERTY_PREFIX+itemFields[2]); + for(HTMLDocument.TextField photo : photos) { + addURIProperty(item, vHITEM.photo, fragment.resolveURI(photo.value())); + } + } + + private void addUrls(HTMLDocument fragment, BNode item) throws ExtractionException { + HTMLDocument.TextField[] links = fragment.getPluralUrlField(Microformats2Prefixes.URL_PROPERTY_PREFIX+ + itemFields[1]); + for (HTMLDocument.TextField link : links) { + conditionallyAddResourceProperty(item, vHITEM.url, getHTMLDocument().resolveURI(link.value())); + } + } +} http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractorFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractorFactory.java b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractorFactory.java new file mode 100644 index 0000000..8423686 --- /dev/null +++ b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HItemExtractorFactory.java @@ -0,0 +1,40 @@ +package org.apache.any23.extractor.html.microformats2; + +import java.util.Arrays; + +import org.apache.any23.extractor.ExtractorDescription; +import org.apache.any23.extractor.ExtractorFactory; +import org.apache.any23.extractor.SimpleExtractorFactory; +import org.apache.any23.rdf.PopularPrefixes; +import org.apache.any23.rdf.Prefixes; + +/** + * @author Nisala Nirmana + * + */ +public class HItemExtractorFactory extends SimpleExtractorFactory<HItemExtractor> implements + ExtractorFactory<HItemExtractor> { + + public static final String NAME = "html-mf2-h-item"; + + public static final Prefixes PREFIXES = PopularPrefixes.createSubset("rdf", "vcard"); + + private static final ExtractorDescription descriptionInstance = new HItemExtractorFactory(); + + public HItemExtractorFactory() { + super( + HItemExtractorFactory.NAME, + HItemExtractorFactory.PREFIXES, + Arrays.asList("text/html;q=0.1", "application/xhtml+xml;q=0.1"), + "example-mf2-h-item.html"); + } + + @Override + public HItemExtractor createExtractor() { + return new HItemExtractor(); + } + + public static ExtractorDescription getDescriptionInstance() { + return descriptionInstance; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractor.java b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractor.java new file mode 100644 index 0000000..d4bf12e --- /dev/null +++ b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractor.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.any23.extractor.html.microformats2; + +import org.apache.any23.extractor.ExtractionException; +import org.apache.any23.extractor.ExtractionResult; +import org.apache.any23.extractor.ExtractorDescription; +import org.apache.any23.vocab.HRecipe; +import org.openrdf.model.BNode; +import org.openrdf.model.URI; +import org.openrdf.model.vocabulary.RDF; +import org.w3c.dom.Node; +import org.apache.any23.extractor.html.EntityBasedMicroformatExtractor; +import org.apache.any23.extractor.html.HTMLDocument; + +/** + * Extractor for the <a href="http://microformats.org/wiki/hrecipe">hRecipe</a> + * microformat. + * + * @author Nisala Nirmana + */ +public class HRecipeExtractor extends EntityBasedMicroformatExtractor { + + private static final HRecipe vHRECIPE = HRecipe.getInstance(); + + private static final String[] recipeFields = { + "name", + "ingredient", + "yield", + "instructions", + "duration", + "photo", + "summary", + "author", + "published", + "nutrition" + }; + + @Override + public ExtractorDescription getDescription() { + return HRecipeExtractorFactory.getDescriptionInstance(); + } + + @Override + protected String getBaseClassName() { + return Microformats2Prefixes.CLASS_PREFIX+"recipe"; + } + + @Override + protected void resetExtractor() { + // Empty. + } + + @Override + protected boolean extractEntity(Node node, ExtractionResult out) throws ExtractionException { + final BNode recipe = getBlankNodeFor(node); + conditionallyAddResourceProperty(recipe, RDF.TYPE, vHRECIPE.Recipe); + final HTMLDocument fragment = new HTMLDocument(node); + addName(fragment, recipe); + addIngredients(fragment, recipe); + addYield(fragment, recipe); + addInstructions(fragment, recipe); + addDurations(fragment, recipe); + addPhoto(fragment, recipe); + addSummary(fragment, recipe); + addAuthors(fragment, recipe); + addPublished(fragment, recipe); + addNutritions(fragment, recipe); + return true; + } + + private void mapFieldWithProperty(HTMLDocument fragment, BNode recipe, String fieldClass, URI property) { + HTMLDocument.TextField title = fragment.getSingularTextField(fieldClass); + conditionallyAddStringProperty( + title.source(), recipe, property, title.value() + ); + } + + private void addName(HTMLDocument fragment, BNode recipe) { + mapFieldWithProperty(fragment, recipe, Microformats2Prefixes.PROPERTY_PREFIX + recipeFields[0], vHRECIPE.fn); + } + + private void addIngredients(HTMLDocument fragment, BNode recipe) { + final HTMLDocument.TextField[] ingredients = fragment.getPluralTextField + (Microformats2Prefixes.PROPERTY_PREFIX+recipeFields[1]); + for(HTMLDocument.TextField ingredient : ingredients) { + conditionallyAddStringProperty( + ingredient.source(), recipe, vHRECIPE.ingredient, ingredient.value() + ); + } + } + + private void addInstructions(HTMLDocument fragment, BNode recipe) { + mapFieldWithProperty(fragment, recipe, Microformats2Prefixes.EMBEDDED_PROPERTY_PREFIX+recipeFields[2], + vHRECIPE.instructions); + } + + private void addYield(HTMLDocument fragment, BNode recipe) { + mapFieldWithProperty(fragment, recipe, Microformats2Prefixes.PROPERTY_PREFIX+recipeFields[3], vHRECIPE.yield); + } + + private void addDurations(HTMLDocument fragment, BNode recipe) { + final HTMLDocument.TextField[] durations = fragment.getPluralTextField( + Microformats2Prefixes.TIME_PROPERTY_PREFIX + recipeFields[4]); + for(HTMLDocument.TextField duration : durations) { + Node attribute=duration.source().getAttributes().getNamedItem("datetime"); + if (attribute==null){ + conditionallyAddStringProperty( + duration.source(), + recipe, vHRECIPE.duration, duration.value() + ); + }else{ + conditionallyAddStringProperty( + duration.source(), + recipe, vHRECIPE.duration, attribute.getNodeValue() + ); + + } + + } + } + + private void addPhoto(HTMLDocument fragment, BNode recipe) throws ExtractionException { + final HTMLDocument.TextField[] photos = fragment.getPluralUrlField + (Microformats2Prefixes.URL_PROPERTY_PREFIX+recipeFields[5]); + for(HTMLDocument.TextField photo : photos) { + addURIProperty(recipe, vHRECIPE.photo, fragment.resolveURI(photo.value())); + } + } + + private void addSummary(HTMLDocument fragment, BNode recipe) { + mapFieldWithProperty(fragment, recipe, Microformats2Prefixes.PROPERTY_PREFIX+recipeFields[6], vHRECIPE.summary); + } + + private void addAuthors(HTMLDocument fragment, BNode recipe) { + final HTMLDocument.TextField[] authors = fragment. + getPluralTextField(Microformats2Prefixes.PROPERTY_PREFIX + recipeFields[7]); + for(HTMLDocument.TextField author : authors) { + conditionallyAddStringProperty( + author.source(), + recipe, vHRECIPE.author, author.value() + ); + } + } + + private void addPublished(HTMLDocument fragment, BNode recipe) { + final HTMLDocument.TextField[] durations = fragment.getPluralTextField( + Microformats2Prefixes.TIME_PROPERTY_PREFIX + recipeFields[8]); + for(HTMLDocument.TextField duration : durations) { + Node attribute=duration.source().getAttributes().getNamedItem("datetime"); + if (attribute==null){ + conditionallyAddStringProperty( + duration.source(), + recipe, vHRECIPE.published, duration.value() + ); + }else{ + conditionallyAddStringProperty( + duration.source(), + recipe, vHRECIPE.published, attribute.getNodeValue() + ); + } + } + } + + private void addNutritions(HTMLDocument fragment, BNode recipe) { + final HTMLDocument.TextField[] nutritions = fragment.getPluralTextField + (Microformats2Prefixes.PROPERTY_PREFIX+recipeFields[9]); + for(HTMLDocument.TextField nutrition : nutritions) { + conditionallyAddStringProperty( + nutrition.source(), recipe, vHRECIPE.nutrition, nutrition.value() + ); + } + } +} http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorFactory.java b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorFactory.java new file mode 100644 index 0000000..2f61f51 --- /dev/null +++ b/core/src/main/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorFactory.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.any23.extractor.html.microformats2; + +import java.util.Arrays; + +import org.apache.any23.extractor.ExtractorDescription; +import org.apache.any23.extractor.ExtractorFactory; +import org.apache.any23.extractor.SimpleExtractorFactory; +import org.apache.any23.rdf.PopularPrefixes; +import org.apache.any23.rdf.Prefixes; + +/** + * @author Nisala Nirmana + * + */ +public class HRecipeExtractorFactory extends SimpleExtractorFactory<HRecipeExtractor> implements + ExtractorFactory<HRecipeExtractor> { + + public static final String NAME = "html-mf2-h-recipe"; + + public static final Prefixes PREFIXES = PopularPrefixes.createSubset("rdf", "hrecipe"); + + private static final ExtractorDescription descriptionInstance = new HRecipeExtractorFactory(); + + public HRecipeExtractorFactory() { + super( + HRecipeExtractorFactory.NAME, + HRecipeExtractorFactory.PREFIXES, + Arrays.asList("text/html;q=0.1", "application/xhtml+xml;q=0.1"), + "example-mf2-h-recipe.html"); + } + + @Override + public HRecipeExtractor createExtractor() { + return new HRecipeExtractor(); + } + + public static ExtractorDescription getDescriptionInstance() { + return descriptionInstance; + } +} http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/test/java/org/apache/any23/extractor/html/microformats2/HItemExtractorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/any23/extractor/html/microformats2/HItemExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/html/microformats2/HItemExtractorTest.java new file mode 100644 index 0000000..8163890 --- /dev/null +++ b/core/src/test/java/org/apache/any23/extractor/html/microformats2/HItemExtractorTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.any23.extractor.html.microformats2; + +import org.apache.any23.extractor.ExtractorFactory; +import org.apache.any23.extractor.html.AbstractExtractorTestCase; +import org.junit.Test; +import org.openrdf.repository.RepositoryException; +import org.openrdf.rio.RDFHandlerException; + +public class HItemExtractorTest extends AbstractExtractorTestCase { + + protected ExtractorFactory<?> getExtractorFactory() { + return new HItemExtractorFactory(); + } + + @Test + public void testModelNotEmpty() throws RepositoryException, RDFHandlerException { + assertExtract("/microformats2/h-item/h-item-test.html"); + assertModelNotEmpty(); + assertStatementsSize(null, null, null, 4); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/core/src/test/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorTest.java new file mode 100644 index 0000000..883a630 --- /dev/null +++ b/core/src/test/java/org/apache/any23/extractor/html/microformats2/HRecipeExtractorTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.any23.extractor.html.microformats2; + +import org.apache.any23.extractor.ExtractorFactory; +import org.apache.any23.extractor.html.AbstractExtractorTestCase; +import org.junit.Test; +import org.openrdf.repository.RepositoryException; +import org.openrdf.rio.RDFHandlerException; + +public class HRecipeExtractorTest extends AbstractExtractorTestCase { + + protected ExtractorFactory<?> getExtractorFactory() { + return new HRecipeExtractorFactory(); + } + + @Test + public void testModelNotEmpty() throws RepositoryException, RDFHandlerException { + assertExtract("/microformats2/h-recipe/h-recipe-test.html"); + assertModelNotEmpty(); + assertStatementsSize(null, null, null, 15); + } + +} http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/test-resources/src/test/resources/microformats2/h-item/h-item-test.html ---------------------------------------------------------------------- diff --git a/test-resources/src/test/resources/microformats2/h-item/h-item-test.html b/test-resources/src/test/resources/microformats2/h-item/h-item-test.html new file mode 100644 index 0000000..dc2b2c7 --- /dev/null +++ b/test-resources/src/test/resources/microformats2/h-item/h-item-test.html @@ -0,0 +1,27 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<html> + <head> + </head> + <body> + <div class="h-item"> + <span class="p-name">food</span> + <span><img class="u-photo" src="http://cargills.com/food/puddings.jpg" /></span> + <a class="u-url" href="http://cargills.com/food/">Online Supermarket</a> + </div> + </body> +</html> http://git-wip-us.apache.org/repos/asf/any23/blob/1616c17c/test-resources/src/test/resources/microformats2/h-recipe/h-recipe-test.html ---------------------------------------------------------------------- diff --git a/test-resources/src/test/resources/microformats2/h-recipe/h-recipe-test.html b/test-resources/src/test/resources/microformats2/h-recipe/h-recipe-test.html new file mode 100644 index 0000000..20ea47b --- /dev/null +++ b/test-resources/src/test/resources/microformats2/h-recipe/h-recipe-test.html @@ -0,0 +1,71 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<html> +<head> + <title>http://microformats.org/wiki/hrecipe Example 1</title> +</head> +<body> +<div class="h-recipe"> + <span class="p-name">Yorkshire Puddings</span> + <span class="p-summary">Makes<span class="p-yield">6 good sized Yorkshire puddings</span>,the way my mum taught me</span> + <span><img class="u-photo" src="http://codebits.glennjones.net/semantic/yorkshire-puddings.jpg" /></span> + + <div> + <h3>Ingredients</h3> + <ul> + <li class="p-ingredient">1 egg</li> + <li class="p-ingredient">75g plain flour</li> + <li class="p-ingredient">70ml milk</li> + <li class="p-ingredient">60ml water</li> + <li class="p-ingredient">Pinch of salt</li> + </ul> + </div> + + <h3>Time</h3> + <ul> + <li>Cook<span class="dt-duration">25 mins</span></li> + </ul> + + + <h3>Instructions</h3> + <div class="e-instructions"> + <ol> + <li>Pre-heat oven to 230C or gas mark 8. Pour the vegetable oil evenly into 2 x 4-hole + Yorkshire pudding tins and place in the oven to heat through.</li> + + <li>To make the batter, add all the flour into a bowl and beat in the eggs until smooth. + Gradually add the milk and water while beating the mixture. It should be smooth and + without lumps. Finally add a pinch of salt.</li> + + <li>Make sure the oil is piping hot before pouring the batter evenly into the tins. + Place in the oven for 20-25 minutes until pudding have risen and look golden brown</li> + </ol> + </div> + + <h3>Nutrition</h3> + <ul> + <li class="p-nutrition">Calories: <span>125</span></li> + <li class="p-nutrition">Fat: <span>3.2g</span></li> + <li class="p-nutrition">Cholesterol: <span>77mg</span></li> + </ul> + + <span>Published on <time class="dt-published" datetime="2011-10-27">27 Oct 2011</time> by + ` <span class="p-author">Glenn Jones</span> + +</div> +</body> +</html>
