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

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: wychen's comments addressed Created 4 years, 5 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.NodeList; 10 import com.google.gwt.dom.client.NodeList;
(...skipping 19 matching lines...) Expand all
30 * The value of a Schema.Org property can be a Schema.Org type, i.e. embedded. E.g., the author or 30 * The value of a Schema.Org property can be a Schema.Org type, i.e. embedded. E.g., the author or
31 * publisher of article or publisher of image could be a Schema.Org Person or Or ganization type; 31 * publisher of article or publisher of image could be a Schema.Org Person or Or ganization type;
32 * in fact, this is the reason we support Person and Organization types. 32 * in fact, this is the reason we support Person and Organization types.
33 */ 33 */
34 public class SchemaOrgParser { 34 public class SchemaOrgParser {
35 static final String NAME_PROP = "name"; 35 static final String NAME_PROP = "name";
36 static final String URL_PROP = "url"; 36 static final String URL_PROP = "url";
37 static final String DESCRIPTION_PROP = "description"; 37 static final String DESCRIPTION_PROP = "description";
38 static final String IMAGE_PROP = "image"; 38 static final String IMAGE_PROP = "image";
39 static final String HEADLINE_PROP = "headline"; 39 static final String HEADLINE_PROP = "headline";
40 static final String MAIN_ENTITY_OF_PAGE = "mainEntityOfPage";
41 static final String MAIN_ENTITY = "mainEntity";
40 static final String PUBLISHER_PROP = "publisher"; 42 static final String PUBLISHER_PROP = "publisher";
41 static final String COPYRIGHT_HOLDER_PROP = "copyrightHolder"; 43 static final String COPYRIGHT_HOLDER_PROP = "copyrightHolder";
42 static final String COPYRIGHT_YEAR_PROP = "copyrightYear"; 44 static final String COPYRIGHT_YEAR_PROP = "copyrightYear";
43 static final String CONTENT_URL_PROP = "contentUrl"; 45 static final String CONTENT_URL_PROP = "contentUrl";
44 static final String ENCODING_FORMAT_PROP = "encodingFormat"; 46 static final String ENCODING_FORMAT_PROP = "encodingFormat";
45 static final String CAPTION_PROP = "caption"; 47 static final String CAPTION_PROP = "caption";
46 static final String REPRESENTATIVE_PROP = "representativeOfPage"; 48 static final String REPRESENTATIVE_PROP = "representativeOfPage";
47 static final String WIDTH_PROP = "width"; 49 static final String WIDTH_PROP = "width";
48 static final String HEIGHT_PROP = "height"; 50 static final String HEIGHT_PROP = "height";
49 static final String DATE_PUBLISHED_PROP = "datePublished"; 51 static final String DATE_PUBLISHED_PROP = "datePublished";
50 static final String DATE_MODIFIED_PROP = "dateModified"; 52 static final String DATE_MODIFIED_PROP = "dateModified";
51 static final String AUTHOR_PROP = "author"; 53 static final String AUTHOR_PROP = "author";
52 static final String CREATOR_PROP = "creator"; 54 static final String CREATOR_PROP = "creator";
53 static final String SECTION_PROP = "articleSection"; 55 static final String SECTION_PROP = "articleSection";
54 static final String ASSOCIATED_MEDIA_PROP = "associatedMedia"; 56 static final String ASSOCIATED_MEDIA_PROP = "associatedMedia";
55 static final String ENCODING_PROP = "encoding"; 57 static final String ENCODING_PROP = "encoding";
56 static final String FAMILY_NAME_PROP = "familyName"; 58 static final String FAMILY_NAME_PROP = "familyName";
57 static final String GIVEN_NAME_PROP = "givenName"; 59 static final String GIVEN_NAME_PROP = "givenName";
58 static final String LEGAL_NAME_PROP = "legalName"; 60 static final String LEGAL_NAME_PROP = "legalName";
59 static final String AUTHOR_REL = "author"; 61 static final String AUTHOR_REL = "author";
62 static final String COOK_TIME = "cookTime";
63 static final String COOKING_METHOD = "cookingMethod";
64 static final String NUTRITION = "nutrition";
65 static final String PREP_TIME = "prepTime";
66 static final String RECIPE_CATEGORY = "recipeCategory";
67 static final String RECIPE_CUISINE = "recipeCuisine";
68 static final String RECIPE_INGREDIENT = "recipeIngredient";
69 static final String INGREDIENTS = "ingredients";
70 static final String RECIPE_INSTRUCTIONS = "recipeInstructions";
71 static final String RECIPE_YIELD = "recipeYield";
72 static final String TOTAL_TIME = "totalTime";
60 73
61 enum Type { // All these types are extended from Thing, directly or indirec tly. 74 enum Type { // All these types are extended from Thing, directly or indirec tly.
62 IMAGE, 75 IMAGE,
63 ARTICLE, 76 ARTICLE,
64 PERSON, 77 PERSON,
65 ORGANIZATION, 78 ORGANIZATION,
79 RECIPE,
66 UNSUPPORTED, 80 UNSUPPORTED,
67 } 81 }
68 82
69 static class ThingItem { 83 static abstract class ThingItem {
70 private final Element mElement; 84 private final Element mElement;
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, Element element) { 89 ThingItem(Type type, Element element) {
76 mElement = element; 90 mElement = element;
77 mType = type; 91 mType = type;
78 mStringProperties = new HashMap<String, String>(); 92 mStringProperties = new HashMap<String, List<String>>();
79 mItemProperties = new HashMap<String, ThingItem>(); 93 mItemProperties = new HashMap<String, ThingItem>();
80 94
81 addStringPropertyName(NAME_PROP); 95 addStringPropertyName(NAME_PROP);
82 addStringPropertyName(URL_PROP); 96 addStringPropertyName(URL_PROP);
83 addStringPropertyName(DESCRIPTION_PROP); 97 addStringPropertyName(DESCRIPTION_PROP);
84 addStringPropertyName(IMAGE_PROP); 98 addStringPropertyName(IMAGE_PROP);
99 addStringPropertyName(MAIN_ENTITY_OF_PAGE);
100 addStringPropertyName(MAIN_ENTITY);
85 } 101 }
86 102
87 final void addStringPropertyName(String name) { 103 final void addStringPropertyName(String name) {
88 mStringProperties.put(name, ""); 104 if (mStringProperties.get(name) == null) {
105 mStringProperties.put(name, new ArrayList<String>());
106 }
89 } 107 }
90 108
91 final void addItemPropertyName(String name) { 109 final void addItemPropertyName(String name) {
92 mItemProperties.put(name, null); 110 mItemProperties.put(name, null);
93 } 111 }
94 112
95 final String getStringProperty(String name) { 113 final String getStringProperty(String name) {
96 return !mStringProperties.containsKey(name) ? "" : mStringProperties .get(name); 114 return !mStringProperties.containsKey(name) ? "" : DomUtil.join(mStr ingProperties.get(name).toArray(), ", ");
115 }
116
117 final List<String> getProperty(String name) {
118 return mStringProperties.get(name);
97 } 119 }
98 120
99 final ThingItem getItemProperty(String name) { 121 final ThingItem getItemProperty(String name) {
100 return !mItemProperties.containsKey(name) ? null : mItemProperties.g et(name); 122 return !mItemProperties.containsKey(name) ? null : mItemProperties.g et(name);
101 } 123 }
102 124
103 final Type getType() { return mType; } 125 final Type getType() { return mType; }
104 126
105 final boolean isSupported() { return mType != Type.UNSUPPORTED; } 127 final boolean isSupported() { return mType != Type.UNSUPPORTED; }
106 128
107 // Store |value| for property with |name|, unless the property already h as a non-empty 129 // Store |value| for property with |name|. Values are added
108 // value, in which case |value| will be ignored. This means we only kee p the first value. 130 // into a list indexed by |name|. Using a list of values is
131 // necessary in order to support duplicated properties like
132 // 'recipeIngredient' which appears frequently more than once
133 // in a Recipe.
109 final void putStringValue(String name, String value) { 134 final void putStringValue(String name, String value) {
110 if (mStringProperties.containsKey(name) && mStringProperties.get(nam e).isEmpty()) { 135 if (mStringProperties.containsKey(name)) {
111 mStringProperties.put(name, value); 136 mStringProperties.get(name).add(value);
112 } 137 }
113 } 138 }
114 139
115 // Store |value| for property with |name|, unless the property already h as a non-null value, 140 // Store |value| for property with |name|, unless the property already h as a non-null value,
116 // in which case, |value| will be ignored. This means we only keep the first value. 141 // in which case, |value| will be ignored. This means we only keep the first value.
117 final void putItemValue(String name, ThingItem value) { 142 final void putItemValue(String name, ThingItem value) {
118 if (mItemProperties.containsKey(name)) mItemProperties.put(name, val ue); 143 if (mItemProperties.containsKey(name)) mItemProperties.put(name, val ue);
119 } 144 }
120 145
146 /**
147 * Derived items should provide their own implementations.
148 *
149 * @return HTML output.
150 */
151 public abstract String generateOutput();
152
121 final Element getElement() { 153 final Element getElement() {
122 return mElement; 154 return mElement;
123 } 155 }
124 } 156 }
125 157
126 private final List<ThingItem> mItemScopes = new ArrayList<ThingItem>(); 158 private final List<ThingItem> mItemScopes = new ArrayList<ThingItem>();
127 private final Map<Element, ThingItem> mItemElement = new HashMap<Element, Th ingItem>(); 159 private final Map<Element, ThingItem> mItemElement = new HashMap<Element, Th ingItem>();
128 private String mAuthorFromRel = ""; 160 private String mAuthorFromRel = "";
129 private static final Map<String, Type> sTypeUrls; 161 private static final Map<String, Type> sTypeUrls;
130 162
131 static { 163 static {
132 sTypeUrls = new HashMap<String, Type>(); 164 sTypeUrls = new HashMap<String, Type>();
133 sTypeUrls.put("http://schema.org/ImageObject", Type.IMAGE); 165 sTypeUrls.put("http://schema.org/ImageObject", Type.IMAGE);
134 sTypeUrls.put("http://schema.org/Article", Type.ARTICLE); 166 sTypeUrls.put("http://schema.org/Article", Type.ARTICLE);
135 sTypeUrls.put("http://schema.org/BlogPosting", Type.ARTICLE); 167 sTypeUrls.put("http://schema.org/BlogPosting", Type.ARTICLE);
136 sTypeUrls.put("http://schema.org/NewsArticle", Type.ARTICLE); 168 sTypeUrls.put("http://schema.org/NewsArticle", Type.ARTICLE);
137 sTypeUrls.put("http://schema.org/ScholarlyArticle", Type.ARTICLE); 169 sTypeUrls.put("http://schema.org/ScholarlyArticle", Type.ARTICLE);
138 sTypeUrls.put("http://schema.org/TechArticle", Type.ARTICLE); 170 sTypeUrls.put("http://schema.org/TechArticle", Type.ARTICLE);
139 sTypeUrls.put("http://schema.org/Person", Type.PERSON); 171 sTypeUrls.put("http://schema.org/Person", Type.PERSON);
140 sTypeUrls.put("http://schema.org/Organization", Type.ORGANIZATION); 172 sTypeUrls.put("http://schema.org/Organization", Type.ORGANIZATION);
141 sTypeUrls.put("http://schema.org/Corporation", Type.ORGANIZATION); 173 sTypeUrls.put("http://schema.org/Corporation", Type.ORGANIZATION);
142 sTypeUrls.put("http://schema.org/EducationalOrganization", Type.ORGANIZA TION); 174 sTypeUrls.put("http://schema.org/EducationalOrganization", Type.ORGANIZA TION);
143 sTypeUrls.put("http://schema.org/GovernmentOrganization", Type.ORGANIZAT ION); 175 sTypeUrls.put("http://schema.org/GovernmentOrganization", Type.ORGANIZAT ION);
144 sTypeUrls.put("http://schema.org/NGO", Type.ORGANIZATION); 176 sTypeUrls.put("http://schema.org/NGO", Type.ORGANIZATION);
177 sTypeUrls.put("http://schema.org/Recipe", Type.RECIPE);
145 } 178 }
146 179
147 private final TimingInfo mTimingInfo; 180 private final TimingInfo mTimingInfo;
148 181
149 /** 182 /**
150 * The object that extracts and verifies Schema.org markup tags from |root|. 183 * The object that extracts and verifies Schema.org markup tags from |root|.
151 */ 184 */
152 public SchemaOrgParser(Element root, TimingInfo timingInfo) { 185 public SchemaOrgParser(Element root, TimingInfo timingInfo) {
153 mTimingInfo = timingInfo; 186 mTimingInfo = timingInfo;
154 double startTime = DomUtil.getTime(); 187 double startTime = DomUtil.getTime();
(...skipping 12 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(e); 343 newItem = new ArticleItem(e);
274 break; 344 break;
275 case PERSON: 345 case PERSON:
276 newItem = new PersonItem(e); 346 newItem = new PersonItem(e);
277 break; 347 break;
278 case ORGANIZATION: 348 case ORGANIZATION:
279 newItem = new OrganizationItem(e); 349 newItem = new OrganizationItem(e);
280 break; 350 break;
351 case RECIPE:
352 newItem = new RecipeItem(e);
353 break;
281 case UNSUPPORTED: 354 case UNSUPPORTED:
282 newItem = new UnsupportedItem(e); 355 newItem = new UnsupportedItem(e);
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(Element element) { 397 ArticleItem(Element element) {
320 super(Type.ARTICLE, element); 398 super(Type.ARTICLE, element);
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(Element element) { 478 PersonItem(Element element) {
396 super(Type.PERSON, element); 479 super(Type.PERSON, element);
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 static class RecipeItem extends ThingItem {
510
511 RecipeItem(Element element) {
512 super(Type.RECIPE, element);
513
514 addStringPropertyName(AUTHOR_PROP);
515 addStringPropertyName(CREATOR_PROP);
516 addStringPropertyName(COOK_TIME);
517 addStringPropertyName(COOKING_METHOD);
518 addStringPropertyName(NUTRITION);
519 addStringPropertyName(PREP_TIME);
520 addStringPropertyName(RECIPE_CATEGORY);
521 addStringPropertyName(RECIPE_CUISINE);
522 addStringPropertyName(RECIPE_INGREDIENT);
523 addStringPropertyName(INGREDIENTS);
524 addStringPropertyName(RECIPE_INSTRUCTIONS);
525 addStringPropertyName(RECIPE_YIELD);
526 addStringPropertyName(TOTAL_TIME);
527
528 addItemPropertyName(AUTHOR_PROP);
529 addItemPropertyName(CREATOR_PROP);
530 }
531
532 final Recipe getRecipe() {
533 Recipe recipe = new Recipe();
534 recipe.title = getStringProperty(NAME_PROP);
535 recipe.imageSrc = getStringProperty(IMAGE_PROP);
536 recipe.cookTime = DomUtil.formatDuration(
537 getStringProperty(COOK_TIME));
538 recipe.author = retrieveProperty(AUTHOR_PROP);
539 recipe.creator = retrieveProperty(CREATOR_PROP);
540 recipe.description = getStringProperty(DESCRIPTION_PROP);
541 recipe.recipeYield = getStringProperty(RECIPE_YIELD);
542 recipe.prepTime = DomUtil.formatDuration(
543 getStringProperty(PREP_TIME));
544 recipe.recipeIngredient = getProperty(RECIPE_INGREDIENT).isEmpty() ?
545 getProperty(INGREDIENTS) : getProperty(RECIPE_INGREDIENT);
546 recipe.recipeInstructions = getProperty(RECIPE_INSTRUCTIONS);
547 recipe.totalTime = DomUtil.formatDuration(
548 getStringProperty(TOTAL_TIME));
549 return recipe;
550 }
551
552 String retrieveProperty(String property) {
553 String value = getStringProperty(property);
554 if(value.isEmpty()) {
555 ThingItem itemProperty = getItemProperty(property);
556 if (itemProperty != null) {
557 value = itemProperty.generateOutput();
558 }
559 }
560 return value;
561 }
562
563 @Override
564 public String generateOutput() {
565 return MarkupGenerator.generateMarkup(getRecipe());
566 }
567
568 class Recipe {
569 String title;
570 String imageSrc;
571 String author;
572 String creator;
573 String description;
574 String recipeYield;
575 String prepTime;
576 String cookTime;
577 String totalTime;
578 List<String> recipeIngredient;
579 List<String> recipeInstructions;
580 }
581 }
582
583 static class OrganizationItem extends ThingItem {
412 OrganizationItem(Element element) { 584 OrganizationItem(Element element) {
413 super(Type.ORGANIZATION, element); 585 super(Type.ORGANIZATION, element);
414 586
415 addStringPropertyName(LEGAL_NAME_PROP); 587 addStringPropertyName(LEGAL_NAME_PROP);
416 } 588 }
417 589
418 String getName() { 590 String getName() {
419 // Returns either the value of NAME_PROP or LEGAL_NAME_PROP. 591 // Returns either the value of NAME_PROP or LEGAL_NAME_PROP.
420 String name = getStringProperty(NAME_PROP); 592 String name = getStringProperty(NAME_PROP);
421 return !name.isEmpty() ? name : getStringProperty(LEGAL_NAME_PROP); 593 return !name.isEmpty() ? name : getStringProperty(LEGAL_NAME_PROP);
422 } 594 }
595
596 @Override
597 public String generateOutput() {
598 return "";
599 }
423 } 600 }
424 601
425 private static class UnsupportedItem extends ThingItem { 602 private static class UnsupportedItem extends ThingItem {
426 UnsupportedItem(Element element) { 603 UnsupportedItem(Element element) {
427 super(Type.UNSUPPORTED, element); 604 super(Type.UNSUPPORTED, element);
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