Chromium Code Reviews| 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 |