OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |