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.NodeList; | 10 import com.google.gwt.dom.client.NodeList; |
(...skipping 19 matching lines...) Expand all Loading... |
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 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(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 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(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 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(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 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 |