Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: java/org/chromium/distiller/SchemaOrgParser.java

Issue 1705123002: Add support for Schema.org/Recipe Base URL: https://github.com/chromium/dom-distiller.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.distiller; 5 package org.chromium.distiller;
6 6
7 import org.chromium.distiller.proto.DomDistillerProtos.TimingInfo; 7 import org.chromium.distiller.proto.DomDistillerProtos.TimingInfo;
8 8
9 import com.google.gwt.dom.client.Element; 9 import com.google.gwt.dom.client.Element;
10 import com.google.gwt.dom.client.Node; 10 import com.google.gwt.dom.client.Node;
(...skipping 20 matching lines...) Expand all
31 * The value of a Schema.Org property can be a Schema.Org type, i.e. embedded. E.g., the author or 31 * The value of a Schema.Org property can be a Schema.Org type, i.e. embedded. E.g., the author or
32 * publisher of article or publisher of image could be a Schema.Org Person or Or ganization type; 32 * publisher of article or publisher of image could be a Schema.Org Person or Or ganization type;
33 * in fact, this is the reason we support Person and Organization types. 33 * in fact, this is the reason we support Person and Organization types.
34 */ 34 */
35 public class SchemaOrgParser { 35 public class SchemaOrgParser {
36 static final String NAME_PROP = "name"; 36 static final String NAME_PROP = "name";
37 static final String URL_PROP = "url"; 37 static final String URL_PROP = "url";
38 static final String DESCRIPTION_PROP = "description"; 38 static final String DESCRIPTION_PROP = "description";
39 static final String IMAGE_PROP = "image"; 39 static final String IMAGE_PROP = "image";
40 static final String HEADLINE_PROP = "headline"; 40 static final String HEADLINE_PROP = "headline";
41 static final String MAIN_ENTITY_OF_PAGE = "mainEntityOfPage";
42 static final String MAIN_ENTITY = "mainEntity";
41 static final String PUBLISHER_PROP = "publisher"; 43 static final String PUBLISHER_PROP = "publisher";
42 static final String COPYRIGHT_HOLDER_PROP = "copyrightHolder"; 44 static final String COPYRIGHT_HOLDER_PROP = "copyrightHolder";
43 static final String COPYRIGHT_YEAR_PROP = "copyrightYear"; 45 static final String COPYRIGHT_YEAR_PROP = "copyrightYear";
44 static final String CONTENT_URL_PROP = "contentUrl"; 46 static final String CONTENT_URL_PROP = "contentUrl";
45 static final String ENCODING_FORMAT_PROP = "encodingFormat"; 47 static final String ENCODING_FORMAT_PROP = "encodingFormat";
46 static final String CAPTION_PROP = "caption"; 48 static final String CAPTION_PROP = "caption";
47 static final String REPRESENTATIVE_PROP = "representativeOfPage"; 49 static final String REPRESENTATIVE_PROP = "representativeOfPage";
48 static final String WIDTH_PROP = "width"; 50 static final String WIDTH_PROP = "width";
49 static final String HEIGHT_PROP = "height"; 51 static final String HEIGHT_PROP = "height";
50 static final String DATE_PUBLISHED_PROP = "datePublished"; 52 static final String DATE_PUBLISHED_PROP = "datePublished";
51 static final String DATE_MODIFIED_PROP = "dateModified"; 53 static final String DATE_MODIFIED_PROP = "dateModified";
52 static final String AUTHOR_PROP = "author"; 54 static final String AUTHOR_PROP = "author";
53 static final String CREATOR_PROP = "creator"; 55 static final String CREATOR_PROP = "creator";
54 static final String SECTION_PROP = "articleSection"; 56 static final String SECTION_PROP = "articleSection";
55 static final String ASSOCIATED_MEDIA_PROP = "associatedMedia"; 57 static final String ASSOCIATED_MEDIA_PROP = "associatedMedia";
56 static final String ENCODING_PROP = "encoding"; 58 static final String ENCODING_PROP = "encoding";
57 static final String FAMILY_NAME_PROP = "familyName"; 59 static final String FAMILY_NAME_PROP = "familyName";
58 static final String GIVEN_NAME_PROP = "givenName"; 60 static final String GIVEN_NAME_PROP = "givenName";
59 static final String LEGAL_NAME_PROP = "legalName"; 61 static final String LEGAL_NAME_PROP = "legalName";
60 static final String AUTHOR_REL = "author"; 62 static final String AUTHOR_REL = "author";
63 static final String COOK_TIME = "cookTime";
64 static final String COOKING_METHOD = "cookingMethod";
65 static final String NUTRITION = "nutrition";
66 static final String PREP_TIME = "prepTime";
67 static final String RECIPE_CATEGORY = "recipeCategory";
68 static final String RECIPE_CUISINE = "recipeCuisine";
69 static final String RECIPE_INGREDIENT = "recipeIngredient";
70 static final String INGREDIENTS = "ingredients";
71 static final String RECIPE_INSTRUCTIONS = "recipeInstructions";
72 static final String RECIPE_YIELD = "recipeYield";
73 static final String TOTAL_TIME = "totalTime";
61 74
62 enum Type { // All these types are extended from Thing, directly or indirec tly. 75 enum Type { // All these types are extended from Thing, directly or indirec tly.
63 IMAGE, 76 IMAGE,
64 ARTICLE, 77 ARTICLE,
65 PERSON, 78 PERSON,
66 ORGANIZATION, 79 ORGANIZATION,
80 RECIPE,
67 UNSUPPORTED, 81 UNSUPPORTED,
68 } 82 }
69 83
70 static class ThingItem { 84 static abstract class ThingItem {
71 private final Type mType; 85 private final Type mType;
72 private final Map<String, String> mStringProperties; 86 private final Map<String, List<String>> mStringProperties;
73 private final Map<String, ThingItem> mItemProperties; 87 private final Map<String, ThingItem> mItemProperties;
74 88
75 ThingItem(Type type) { 89 ThingItem(Type type) {
76 mType = type; 90 mType = type;
77 mStringProperties = new HashMap<String, String>(); 91 mStringProperties = new HashMap<String, List<String>>();
78 mItemProperties = new HashMap<String, ThingItem>(); 92 mItemProperties = new HashMap<String, ThingItem>();
79 93
80 addStringPropertyName(NAME_PROP); 94 addStringPropertyName(NAME_PROP);
81 addStringPropertyName(URL_PROP); 95 addStringPropertyName(URL_PROP);
82 addStringPropertyName(DESCRIPTION_PROP); 96 addStringPropertyName(DESCRIPTION_PROP);
83 addStringPropertyName(IMAGE_PROP); 97 addStringPropertyName(IMAGE_PROP);
98 addStringPropertyName(MAIN_ENTITY_OF_PAGE);
99 addStringPropertyName(MAIN_ENTITY);
84 } 100 }
85 101
86 final void addStringPropertyName(String name) { 102 final void addStringPropertyName(String name) {
87 mStringProperties.put(name, ""); 103 if (mStringProperties.get(name) == null) {
104 mStringProperties.put(name, new ArrayList<String>());
105 }
88 } 106 }
89 107
90 final void addItemPropertyName(String name) { 108 final void addItemPropertyName(String name) {
91 mItemProperties.put(name, null); 109 mItemProperties.put(name, null);
92 } 110 }
93 111
94 final String getStringProperty(String name) { 112 final String getStringProperty(String name) {
95 return !mStringProperties.containsKey(name) ? "" : mStringProperties .get(name); 113 return !mStringProperties.containsKey(name) ? "" : DomUtil.join(mStr ingProperties.get(name).toArray(), ", ");
wychen 2016/03/14 22:58:42 Possible l10n issues here. Not all languages use "
114 }
115
116 final List<String> getProperty(String name) {
117 return mStringProperties.get(name);
96 } 118 }
97 119
98 final ThingItem getItemProperty(String name) { 120 final ThingItem getItemProperty(String name) {
99 return !mItemProperties.containsKey(name) ? null : mItemProperties.g et(name); 121 return !mItemProperties.containsKey(name) ? null : mItemProperties.g et(name);
100 } 122 }
101 123
102 final Type getType() { return mType; } 124 final Type getType() { return mType; }
103 125
104 final boolean isSupported() { return mType != Type.UNSUPPORTED; } 126 final boolean isSupported() { return mType != Type.UNSUPPORTED; }
105 127
106 // Store |value| for property with |name|, unless the property already h as a non-empty 128 // Store |value| for property with |name|. Values are added
107 // value, in which case |value| will be ignored. This means we only kee p the first value. 129 // into a list indexed by |name|. Using a list of values is
130 // necessary in order to support duplicated properties like
131 // 'recipeIngredient' which appears frequently more than once
132 // in a Recipe.
108 final void putStringValue(String name, String value) { 133 final void putStringValue(String name, String value) {
109 if (mStringProperties.containsKey(name) && mStringProperties.get(nam e).isEmpty()) { 134 if (mStringProperties.containsKey(name)) {
110 mStringProperties.put(name, value); 135 mStringProperties.get(name).add(value);
111 } 136 }
112 } 137 }
113 138
114 // Store |value| for property with |name|, unless the property already h as a non-null value, 139 // Store |value| for property with |name|, unless the property already h as a non-null value,
115 // in which case, |value| will be ignored. This means we only keep the first value. 140 // in which case, |value| will be ignored. This means we only keep the first value.
116 final void putItemValue(String name, ThingItem value) { 141 final void putItemValue(String name, ThingItem value) {
117 if (mItemProperties.containsKey(name)) mItemProperties.put(name, val ue); 142 if (mItemProperties.containsKey(name)) mItemProperties.put(name, val ue);
118 } 143 }
144
145 /**
146 * Derived items should provide their own implementations.
147 *
148 * @return HTML output.
149 */
150 public abstract String generateOutput();
119 } 151 }
120 152
121 private final List<ThingItem> mItemScopes = new ArrayList<ThingItem>(); 153 private final List<ThingItem> mItemScopes = new ArrayList<ThingItem>();
122 private final Map<Element, ThingItem> mItemElement = new HashMap<Element, Th ingItem>(); 154 private final Map<Element, ThingItem> mItemElement = new HashMap<Element, Th ingItem>();
123 private String mAuthorFromRel = ""; 155 private String mAuthorFromRel = "";
124 private static final Map<String, Type> sTypeUrls; 156 private static final Map<String, Type> sTypeUrls;
125 157
126 static { 158 static {
127 sTypeUrls = new HashMap<String, Type>(); 159 sTypeUrls = new HashMap<String, Type>();
128 sTypeUrls.put("http://schema.org/ImageObject", Type.IMAGE); 160 sTypeUrls.put("http://schema.org/ImageObject", Type.IMAGE);
129 sTypeUrls.put("http://schema.org/Article", Type.ARTICLE); 161 sTypeUrls.put("http://schema.org/Article", Type.ARTICLE);
130 sTypeUrls.put("http://schema.org/BlogPosting", Type.ARTICLE); 162 sTypeUrls.put("http://schema.org/BlogPosting", Type.ARTICLE);
131 sTypeUrls.put("http://schema.org/NewsArticle", Type.ARTICLE); 163 sTypeUrls.put("http://schema.org/NewsArticle", Type.ARTICLE);
132 sTypeUrls.put("http://schema.org/ScholarlyArticle", Type.ARTICLE); 164 sTypeUrls.put("http://schema.org/ScholarlyArticle", Type.ARTICLE);
133 sTypeUrls.put("http://schema.org/TechArticle", Type.ARTICLE); 165 sTypeUrls.put("http://schema.org/TechArticle", Type.ARTICLE);
134 sTypeUrls.put("http://schema.org/Person", Type.PERSON); 166 sTypeUrls.put("http://schema.org/Person", Type.PERSON);
135 sTypeUrls.put("http://schema.org/Organization", Type.ORGANIZATION); 167 sTypeUrls.put("http://schema.org/Organization", Type.ORGANIZATION);
136 sTypeUrls.put("http://schema.org/Corporation", Type.ORGANIZATION); 168 sTypeUrls.put("http://schema.org/Corporation", Type.ORGANIZATION);
137 sTypeUrls.put("http://schema.org/EducationalOrganization", Type.ORGANIZA TION); 169 sTypeUrls.put("http://schema.org/EducationalOrganization", Type.ORGANIZA TION);
138 sTypeUrls.put("http://schema.org/GovernmentOrganization", Type.ORGANIZAT ION); 170 sTypeUrls.put("http://schema.org/GovernmentOrganization", Type.ORGANIZAT ION);
139 sTypeUrls.put("http://schema.org/NGO", Type.ORGANIZATION); 171 sTypeUrls.put("http://schema.org/NGO", Type.ORGANIZATION);
172 sTypeUrls.put("http://schema.org/Recipe", Type.RECIPE);
140 } 173 }
141 174
142 private final TimingInfo mTimingInfo; 175 private final TimingInfo mTimingInfo;
143 176
144 /** 177 /**
145 * The object that extracts and verifies Schema.org markup tags from |root|. 178 * The object that extracts and verifies Schema.org markup tags from |root|.
146 */ 179 */
147 public SchemaOrgParser(Element root, TimingInfo timingInfo) { 180 public SchemaOrgParser(Element root, TimingInfo timingInfo) {
148 // TODO(kuan): Parsing all tags is pretty expensive, should we do so onl y lazily? 181 // TODO(kuan): Parsing all tags is pretty expensive, should we do so onl y lazily?
149 // If parse lazily, all get* methods will need to check for parsed state and, if necessary, 182 // If parse lazily, all get* methods will need to check for parsed state and, if necessary,
(...skipping 17 matching lines...) Expand all
167 200
168 final List<ImageItem> getImageItems() { 201 final List<ImageItem> getImageItems() {
169 List<ImageItem> images = new ArrayList<ImageItem>(); 202 List<ImageItem> images = new ArrayList<ImageItem>();
170 for (int i = 0; i < mItemScopes.size(); i++) { 203 for (int i = 0; i < mItemScopes.size(); i++) {
171 ThingItem item = mItemScopes.get(i); 204 ThingItem item = mItemScopes.get(i);
172 if (item.mType == Type.IMAGE) images.add((ImageItem) item); 205 if (item.mType == Type.IMAGE) images.add((ImageItem) item);
173 } 206 }
174 return images; 207 return images;
175 } 208 }
176 209
210 /**
211 * Get the main entity of a page if any.
212 *
213 * Main entity of a page is retrieved by the mainEntityOfPage
214 * or by its inverse property mainEntity.
215 *
216 * @return ThingItem which is the main entity of this page.
217 */
218 final ThingItem getMainEntity() {
219 for (ThingItem mItemScope : mItemScopes) {
220 if(!mItemScope.getStringProperty(MAIN_ENTITY).isEmpty() ||
221 !mItemScope.getStringProperty(MAIN_ENTITY_OF_PAGE).isEmpty() ) {
222 return mItemScope;
223 }
224 }
225 return null;
226 }
227
228 /**
229 * Look for all top level entities on the page. As we are
230 * representing the graph hierarchy by having a set of
231 * children in every node, the top level entities (roots) are those
232 * nodes that do not appear as children in any other node.
233 *
234 * @return List<ThingItem> which are considered top level entities.
235 */
236 final List<ThingItem> getTopLevelEntities() {
237 List<ThingItem> candidates = new ArrayList<>(mItemScopes);
238 for (ThingItem mItemScope : mItemScopes) {
239 for (Map.Entry<String, ThingItem> entry :
240 mItemScope.mItemProperties.entrySet()) {
241 candidates.remove(entry.getValue());
242 }
243 }
244 return candidates;
245 }
246
177 final String getAuthorFromRel() { return mAuthorFromRel; } 247 final String getAuthorFromRel() { return mAuthorFromRel; }
178 248
179 private void parse(Element root) { 249 private void parse(Element root) {
180 NodeList<Element> allProp = DomUtil.querySelectorAll(root, "[ITEMPROP],[ ITEMSCOPE]"); 250 NodeList<Element> allProp = DomUtil.querySelectorAll(root, "[ITEMPROP],[ ITEMSCOPE]");
181 251
182 // Root node (html) is not included in the result of querySelectorAll, s o need to 252 // Root node (html) is not included in the result of querySelectorAll, s o need to
183 // handle it explicitly here. 253 // handle it explicitly here.
184 parseElement(root, null); 254 parseElement(root, null);
185 255
186 for (int i = 0; i < allProp.getLength(); i++) { 256 for (int i = 0; i < allProp.getLength(); i++) {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 break; 341 break;
272 case ARTICLE: 342 case ARTICLE:
273 newItem = new ArticleItem(); 343 newItem = new ArticleItem();
274 break; 344 break;
275 case PERSON: 345 case PERSON:
276 newItem = new PersonItem(); 346 newItem = new PersonItem();
277 break; 347 break;
278 case ORGANIZATION: 348 case ORGANIZATION:
279 newItem = new OrganizationItem(); 349 newItem = new OrganizationItem();
280 break; 350 break;
351 case RECIPE:
352 newItem = new RecipeItem();
353 break;
281 case UNSUPPORTED: 354 case UNSUPPORTED:
282 newItem = new UnsupportedItem(); 355 newItem = new UnsupportedItem();
283 break; 356 break;
284 default: 357 default:
285 return null; 358 return null;
286 } 359 }
287 return newItem; 360 return newItem;
288 } 361 }
289 362
290 static class ImageItem extends ThingItem { 363 static class ImageItem extends ThingItem {
(...skipping 15 matching lines...) Expand all
306 final MarkupParser.Image getImage() { 379 final MarkupParser.Image getImage() {
307 MarkupParser.Image image = new MarkupParser.Image(); 380 MarkupParser.Image image = new MarkupParser.Image();
308 image.url = getStringProperty(CONTENT_URL_PROP); 381 image.url = getStringProperty(CONTENT_URL_PROP);
309 if (image.url.isEmpty()) image.url = getStringProperty(URL_PROP); 382 if (image.url.isEmpty()) image.url = getStringProperty(URL_PROP);
310 image.type = getStringProperty(ENCODING_FORMAT_PROP); 383 image.type = getStringProperty(ENCODING_FORMAT_PROP);
311 image.caption = getStringProperty(CAPTION_PROP); 384 image.caption = getStringProperty(CAPTION_PROP);
312 image.width = JavaScript.parseInt(getStringProperty(WIDTH_PROP), 10) ; 385 image.width = JavaScript.parseInt(getStringProperty(WIDTH_PROP), 10) ;
313 image.height = JavaScript.parseInt(getStringProperty(HEIGHT_PROP), 1 0); 386 image.height = JavaScript.parseInt(getStringProperty(HEIGHT_PROP), 1 0);
314 return image; 387 return image;
315 } 388 }
389
390 @Override
391 public String generateOutput() {
392 return "";
393 }
316 } 394 }
317 395
318 static class ArticleItem extends ThingItem { 396 static class ArticleItem extends ThingItem {
319 ArticleItem() { 397 ArticleItem() {
320 super(Type.ARTICLE); 398 super(Type.ARTICLE);
321 399
322 addStringPropertyName(HEADLINE_PROP); 400 addStringPropertyName(HEADLINE_PROP);
323 addStringPropertyName(PUBLISHER_PROP); 401 addStringPropertyName(PUBLISHER_PROP);
324 addStringPropertyName(COPYRIGHT_HOLDER_PROP); 402 addStringPropertyName(COPYRIGHT_HOLDER_PROP);
325 addStringPropertyName(COPYRIGHT_YEAR_PROP); 403 addStringPropertyName(COPYRIGHT_YEAR_PROP);
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 } 460 }
383 461
384 final MarkupParser.Image getImage() { 462 final MarkupParser.Image getImage() {
385 // Use value of "image" property to create a MarkupParser.Image. 463 // Use value of "image" property to create a MarkupParser.Image.
386 String imageUrl = getStringProperty(IMAGE_PROP); 464 String imageUrl = getStringProperty(IMAGE_PROP);
387 if (imageUrl.isEmpty()) return null; 465 if (imageUrl.isEmpty()) return null;
388 MarkupParser.Image image = new MarkupParser.Image(); 466 MarkupParser.Image image = new MarkupParser.Image();
389 image.url = imageUrl; 467 image.url = imageUrl;
390 return image; 468 return image;
391 } 469 }
470
471 @Override
472 public String generateOutput() {
473 return "";
474 }
392 } 475 }
393 476
394 private static class PersonItem extends ThingItem { 477 static class PersonItem extends ThingItem {
395 PersonItem() { 478 PersonItem() {
396 super(Type.PERSON); 479 super(Type.PERSON);
397 480
398 addStringPropertyName(FAMILY_NAME_PROP); 481 addStringPropertyName(FAMILY_NAME_PROP);
399 addStringPropertyName(GIVEN_NAME_PROP); 482 addStringPropertyName(GIVEN_NAME_PROP);
400 } 483 }
401 484
402 String getName() { 485 String getName() {
403 // Returns either the value of NAME_PROP, or concatenated values of GIVEN_NAME_PROP and 486 // Returns either the value of NAME_PROP, or concatenated values of GIVEN_NAME_PROP and
404 // FAMILY_NAME_PROP delimited by a whitespace. 487 // FAMILY_NAME_PROP delimited by a whitespace.
405 String name = getStringProperty(NAME_PROP); 488 String name = getStringProperty(NAME_PROP);
406 return !name.isEmpty() ? name : 489 return !name.isEmpty() ? name :
407 concat(getStringProperty(GIVEN_NAME_PROP), getStringProperty (FAMILY_NAME_PROP)); 490 concat(getStringProperty(GIVEN_NAME_PROP), getStringProperty (FAMILY_NAME_PROP));
408 } 491 }
492
493 Person getPerson() {
494 Person person = new Person();
495 person.name = getName();
496 return person;
497 }
498
499 class Person {
500 String name;
501 }
502
503 @Override
504 public String generateOutput() {
505 return MarkupGenerator.generateMarkup(getPerson());
506 }
409 } 507 }
410 508
411 private static class OrganizationItem extends ThingItem { 509 private static class OrganizationItem extends ThingItem {
412 OrganizationItem() { 510 OrganizationItem() {
413 super(Type.ORGANIZATION); 511 super(Type.ORGANIZATION);
414 512
415 addStringPropertyName(LEGAL_NAME_PROP); 513 addStringPropertyName(LEGAL_NAME_PROP);
416 } 514 }
417 515
418 String getName() { 516 String getName() {
419 // Returns either the value of NAME_PROP or LEGAL_NAME_PROP. 517 // Returns either the value of NAME_PROP or LEGAL_NAME_PROP.
420 String name = getStringProperty(NAME_PROP); 518 String name = getStringProperty(NAME_PROP);
421 return !name.isEmpty() ? name : getStringProperty(LEGAL_NAME_PROP); 519 return !name.isEmpty() ? name : getStringProperty(LEGAL_NAME_PROP);
422 } 520 }
521
522 @Override
523 public String generateOutput() {
524 return "";
525 }
526 }
527
528 static class RecipeItem extends ThingItem {
529
530 RecipeItem() {
531 super(Type.RECIPE);
532
533 addStringPropertyName(AUTHOR_PROP);
534 addStringPropertyName(CREATOR_PROP);
535 addStringPropertyName(COOK_TIME);
536 addStringPropertyName(COOKING_METHOD);
537 addStringPropertyName(NUTRITION);
538 addStringPropertyName(PREP_TIME);
539 addStringPropertyName(RECIPE_CATEGORY);
540 addStringPropertyName(RECIPE_CUISINE);
541 addStringPropertyName(RECIPE_INGREDIENT);
542 addStringPropertyName(INGREDIENTS);
543 addStringPropertyName(RECIPE_INSTRUCTIONS);
544 addStringPropertyName(RECIPE_YIELD);
545 addStringPropertyName(TOTAL_TIME);
546
547 addItemPropertyName(AUTHOR_PROP);
548 addItemPropertyName(CREATOR_PROP);
549 }
550
551 final Recipe getRecipe() {
552 Recipe recipe = new Recipe();
553 recipe.title = getStringProperty(NAME_PROP);
554 recipe.imageSrc = getStringProperty(IMAGE_PROP);
555 recipe.cookTime = DomUtil.formatDuration(
556 getStringProperty(COOK_TIME));
557 recipe.author = retrieveProperty(AUTHOR_PROP);
558 recipe.creator = retrieveProperty(CREATOR_PROP);
559 recipe.description = getStringProperty(DESCRIPTION_PROP);
560 recipe.recipeYield = getStringProperty(RECIPE_YIELD);
561 recipe.prepTime = DomUtil.formatDuration(
562 getStringProperty(PREP_TIME));
563 recipe.recipeIngredient = getProperty(RECIPE_INGREDIENT).isEmpty() ?
564 getProperty(INGREDIENTS) : getProperty(RECIPE_INGREDIENT);
565 recipe.recipeInstructions = getProperty(RECIPE_INSTRUCTIONS);
566 recipe.totalTime = DomUtil.formatDuration(
567 getStringProperty(TOTAL_TIME));
568 return recipe;
569 }
570
571 String retrieveProperty(String property) {
572 String value = getStringProperty(property);
573 if(value.isEmpty()) {
574 ThingItem itemProperty = getItemProperty(property);
575 if (itemProperty != null) {
576 value = itemProperty.generateOutput();
577 }
578 }
579 return value;
580 }
581
582 @Override
583 public String generateOutput() {
584 return MarkupGenerator.generateMarkup(getRecipe());
585 }
586
587 class Recipe {
588 String title;
589 String imageSrc;
590 String author;
591 String creator;
592 String description;
593 String recipeYield;
594 String prepTime;
595 String cookTime;
596 String totalTime;
597 List<String> recipeIngredient;
598 List<String> recipeInstructions;
599 }
423 } 600 }
424 601
425 private static class UnsupportedItem extends ThingItem { 602 private static class UnsupportedItem extends ThingItem {
426 UnsupportedItem() { 603 UnsupportedItem() {
427 super(Type.UNSUPPORTED); 604 super(Type.UNSUPPORTED);
428 } 605 }
606
607 @Override
608 public String generateOutput() {
609 return "";
610 }
429 } 611 }
430 612
431 private static boolean isItemScope(Element e) { 613 private static boolean isItemScope(Element e) {
432 return e.hasAttribute("ITEMSCOPE") && e.hasAttribute("ITEMTYPE"); 614 return e.hasAttribute("ITEMSCOPE") && e.hasAttribute("ITEMTYPE");
433 } 615 }
434 616
435 private static String[] getItemProp(Element e) { 617 private static String[] getItemProp(Element e) {
436 // "itemprop" attribute is case-sensitive, and can have multiple propert ies. 618 // "itemprop" attribute is case-sensitive, and can have multiple propert ies.
437 String itemprop = e.getAttribute("ITEMPROP"); 619 String itemprop = e.getAttribute("ITEMPROP");
438 if (itemprop.isEmpty()) return new String[0]; 620 if (itemprop.isEmpty()) return new String[0];
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 return author; 673 return author;
492 } 674 }
493 675
494 private static String concat(String first, String second) { 676 private static String concat(String first, String second) {
495 String concat = first; 677 String concat = first;
496 if (!concat.isEmpty() && !second.isEmpty()) concat += " "; 678 if (!concat.isEmpty() && !second.isEmpty()) concat += " ";
497 concat += second; 679 concat += second;
498 return concat; 680 return concat;
499 } 681 }
500 } 682 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698