Merge pull request #45 from ThorKarlsson/GoogleImageExtension
Google image extension
This commit is contained in:
commit
6a605cf6ce
|
@ -0,0 +1,103 @@
|
|||
package com.redfin.sitemapgenerator;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Builds a sitemap for Google Image search. To configure options use {@link #builder(URL, File)}
|
||||
* @see <a href="https://support.google.com/webmasters/answer/183668">Manage your sitemaps</a>
|
||||
* */
|
||||
public class GoogleImageSitemapGenerator extends SitemapGenerator<GoogleImageSitemapUrl, GoogleImageSitemapGenerator> {
|
||||
|
||||
GoogleImageSitemapGenerator(AbstractSitemapGeneratorOptions<?> options) {
|
||||
super(options, new GoogleImageSitemapGenerator.Renderer());
|
||||
}
|
||||
|
||||
/** Configures the generator with a base URL and directory to write the sitemap files.
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
* @param baseDir Sitemap files will be generated in this directory as either "sitemap.xml" or "sitemap1.xml" "sitemap2.xml" and so on.
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public GoogleImageSitemapGenerator(String baseUrl, File baseDir)
|
||||
throws MalformedURLException {
|
||||
this(new SitemapGeneratorOptions(baseUrl, baseDir));
|
||||
}
|
||||
|
||||
/**Configures the generator with a base URL and directory to write the sitemap files.
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
* @param baseDir Sitemap files will be generated in this directory as either "sitemap.xml" or "sitemap1.xml" "sitemap2.xml" and so on.
|
||||
*/
|
||||
public GoogleImageSitemapGenerator(URL baseUrl, File baseDir) {
|
||||
this(new SitemapGeneratorOptions(baseUrl, baseDir));
|
||||
}
|
||||
|
||||
/**Configures the generator with a base URL and a null directory. The object constructed
|
||||
* is not intended to be used to write to files. Rather, it is intended to be used to obtain
|
||||
* XML-formatted strings that represent sitemaps.
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
*/
|
||||
public GoogleImageSitemapGenerator(String baseUrl) throws MalformedURLException {
|
||||
this(new SitemapGeneratorOptions(new URL(baseUrl)));
|
||||
}
|
||||
|
||||
/**Configures the generator with a base URL and a null directory. The object constructed
|
||||
* is not intended to be used to write to files. Rather, it is intended to be used to obtain
|
||||
* XML-formatted strings that represent sitemaps.
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
*/
|
||||
public GoogleImageSitemapGenerator(URL baseUrl) {
|
||||
this(new SitemapGeneratorOptions(baseUrl));
|
||||
}
|
||||
|
||||
/** Configures a builder so you can specify sitemap generator options
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
* @param baseDir Sitemap files will be generated in this directory as either "sitemap.xml" or "sitemap1.xml" "sitemap2.xml" and so on.
|
||||
* @return a builder; call .build() on it to make a sitemap generator
|
||||
*/
|
||||
public static SitemapGeneratorBuilder<GoogleImageSitemapGenerator> builder(URL baseUrl, File baseDir) {
|
||||
return new SitemapGeneratorBuilder<GoogleImageSitemapGenerator>(baseUrl, baseDir, GoogleImageSitemapGenerator.class);
|
||||
}
|
||||
|
||||
/** Configures a builder so you can specify sitemap generator options
|
||||
*
|
||||
* @param baseUrl All URLs in the generated sitemap(s) should appear under this base URL
|
||||
* @param baseDir Sitemap files will be generated in this directory as either "sitemap.xml" or "sitemap1.xml" "sitemap2.xml" and so on.
|
||||
* @return a builder; call .build() on it to make a sitemap generator
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public static SitemapGeneratorBuilder<GoogleImageSitemapGenerator> builder(String baseUrl, File baseDir) throws MalformedURLException {
|
||||
return new SitemapGeneratorBuilder<GoogleImageSitemapGenerator>(baseUrl, baseDir, GoogleImageSitemapGenerator.class);
|
||||
}
|
||||
|
||||
private static class Renderer extends AbstractSitemapUrlRenderer<GoogleImageSitemapUrl> implements ISitemapUrlRenderer<GoogleImageSitemapUrl> {
|
||||
|
||||
public Class<GoogleImageSitemapUrl> getUrlClass() {
|
||||
return GoogleImageSitemapUrl.class;
|
||||
}
|
||||
|
||||
public String getXmlNamespaces() {
|
||||
return "xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\"";
|
||||
}
|
||||
|
||||
public void render(GoogleImageSitemapUrl url, StringBuilder sb, W3CDateFormat dateFormat) {
|
||||
StringBuilder tagSb = new StringBuilder();
|
||||
|
||||
for(Image image : url.getImages()) {
|
||||
tagSb.append(" <image:image>\n");
|
||||
renderTag(tagSb, "image", "loc", image.getUrl());
|
||||
renderTag(tagSb, "image", "caption", image.getCaption());
|
||||
renderTag(tagSb, "image", "title", image.getTitle());
|
||||
renderTag(tagSb, "image", "geo_location", image.getGeoLocation());
|
||||
renderTag(tagSb, "image", "license", image.getLicense());
|
||||
tagSb.append(" </image:image>\n");
|
||||
}
|
||||
super.render(url, sb, dateFormat, tagSb.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.redfin.sitemapgenerator;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** One configurable Google Image Search URL. To configure, use {@link Options}
|
||||
*
|
||||
* @see Options
|
||||
* @see <a href="http://www.google.com/support/webmasters/bin/answer.py?answer=183668">Creating Image Sitemaps</a>
|
||||
*/
|
||||
public class GoogleImageSitemapUrl extends WebSitemapUrl {
|
||||
|
||||
private final List<Image> images;
|
||||
|
||||
public GoogleImageSitemapUrl(String url) throws MalformedURLException {
|
||||
this(new Options(url));
|
||||
}
|
||||
|
||||
public GoogleImageSitemapUrl(URL url) {
|
||||
this(new Options(url));
|
||||
}
|
||||
|
||||
public GoogleImageSitemapUrl(Options options) {
|
||||
super(options);
|
||||
this.images = options.images;
|
||||
}
|
||||
|
||||
public void addImage(Image image) {
|
||||
this.images.add(image);
|
||||
if(this.images.size() > 1000) {
|
||||
throw new RuntimeException("A URL cannot have more than 1000 image tags");
|
||||
}
|
||||
}
|
||||
|
||||
/** Options to configure Google Extension URLs */
|
||||
public static class Options extends AbstractSitemapUrlOptions<GoogleImageSitemapUrl, GoogleImageSitemapUrl.Options> {
|
||||
private List<Image> images;
|
||||
|
||||
|
||||
public Options(URL url) {
|
||||
super(url, GoogleImageSitemapUrl.class);
|
||||
images = new ArrayList<Image>();
|
||||
}
|
||||
|
||||
public Options(String url) throws MalformedURLException {
|
||||
super(url, GoogleImageSitemapUrl.class);
|
||||
images = new ArrayList<Image>();
|
||||
}
|
||||
|
||||
public Options images(List<Image> images) {
|
||||
if(images != null && images.size() > 1000) {
|
||||
throw new RuntimeException("A URL cannot have more than 1000 image tags");
|
||||
}
|
||||
this.images = images;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options images(Image...images) {
|
||||
if(images.length > 1000) {
|
||||
throw new RuntimeException("A URL cannot have more than 1000 image tags");
|
||||
}
|
||||
return images(Arrays.asList(images));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**Retrieves list of images*/
|
||||
public List<Image> getImages() {
|
||||
return this.images;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.redfin.sitemapgenerator;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Represent a single image and image properties for use in extended sitemaps
|
||||
* @see <a href="https://support.google.com/webmasters/answer/178636">Image sitemaps</a>
|
||||
*/
|
||||
public class Image {
|
||||
private final URL url;
|
||||
private final String title;
|
||||
private final String caption;
|
||||
private final String geoLocation;
|
||||
private final URL license;
|
||||
|
||||
public Image(String url) throws MalformedURLException {
|
||||
this(new URL(url));
|
||||
}
|
||||
|
||||
public Image(URL url) {
|
||||
this.url = url;
|
||||
this.title = null;
|
||||
this.caption = null;
|
||||
this.geoLocation = null;
|
||||
this.license = null;
|
||||
}
|
||||
|
||||
public Image(URL url, String title, String caption, String geoLocation, String license) throws MalformedURLException {
|
||||
this(url, title, caption, geoLocation, new URL(license));
|
||||
}
|
||||
|
||||
public Image(URL url, String title, String caption, String geoLocation, URL license) {
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
this.caption = caption;
|
||||
this.geoLocation = geoLocation;
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
|
||||
/** Retrieves URL of Image*/
|
||||
public URL getUrl() { return url; }
|
||||
|
||||
/** Retrieves title of image*/
|
||||
public String getTitle() { return title; }
|
||||
|
||||
/** Retrieves captionof image*/
|
||||
public String getCaption() { return caption; }
|
||||
|
||||
/** Retrieves geolocation string of image*/
|
||||
public String getGeoLocation() { return geoLocation; }
|
||||
|
||||
/** Retrieves license string of image*/
|
||||
public URL getLicense() { return license; }
|
||||
|
||||
public static class ImageBuilder {
|
||||
private URL url;
|
||||
private String title;
|
||||
private String caption;
|
||||
private String geoLocation;
|
||||
private URL license;
|
||||
|
||||
public ImageBuilder(String url) throws MalformedURLException {
|
||||
this(new URL(url));
|
||||
}
|
||||
|
||||
public ImageBuilder(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public ImageBuilder title(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageBuilder caption(String caption) {
|
||||
this.caption = caption;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageBuilder geoLocation(String geoLocation) {
|
||||
this.geoLocation = geoLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ImageBuilder license(String license) throws MalformedURLException {
|
||||
return license(new URL(license));
|
||||
}
|
||||
|
||||
public ImageBuilder license(URL license) {
|
||||
this.license = license;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Image build() {
|
||||
return new Image(url, title, caption, geoLocation, license);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.redfin.sitemapgenerator;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class GoogleImageSitemapUrlTest extends TestCase {
|
||||
|
||||
private static final URL LANDING_URL = newURL("http://www.example.com/index.html");
|
||||
private static final URL CONTENT_URL = newURL("http://www.example.com/index.flv");
|
||||
File dir;
|
||||
GoogleImageSitemapGenerator wsg;
|
||||
|
||||
private static URL newURL(String url) {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (MalformedURLException e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
dir = File.createTempFile(GoogleVideoSitemapUrlTest.class.getSimpleName(), "");
|
||||
dir.delete();
|
||||
dir.mkdir();
|
||||
dir.deleteOnExit();
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
wsg = null;
|
||||
for (File file : dir.listFiles()) {
|
||||
file.deleteOnExit();
|
||||
file.delete();
|
||||
}
|
||||
dir.delete();
|
||||
dir = null;
|
||||
}
|
||||
|
||||
public void testSimpleUrl() throws Exception {
|
||||
wsg = new GoogleImageSitemapGenerator("http://www.example.com", dir);
|
||||
GoogleImageSitemapUrl url = new GoogleImageSitemapUrl(LANDING_URL);
|
||||
url.addImage(new Image("http://cdn.example.com/image1.jpg"));
|
||||
url.addImage(new Image("http://cdn.example.com/image2.jpg"));
|
||||
wsg.addUrl(url);
|
||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\" >\n" +
|
||||
" <url>\n" +
|
||||
" <loc>http://www.example.com/index.html</loc>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image1.jpg</image:loc>\n" +
|
||||
" </image:image>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image2.jpg</image:loc>\n" +
|
||||
" </image:image>\n" +
|
||||
" </url>\n" +
|
||||
"</urlset>";
|
||||
String sitemap = writeSingleSiteMap(wsg);
|
||||
assertEquals(expected, sitemap);
|
||||
}
|
||||
|
||||
public void testBaseOptions() throws Exception {
|
||||
wsg = new GoogleImageSitemapGenerator("http://www.example.com", dir);
|
||||
GoogleImageSitemapUrl url = new GoogleImageSitemapUrl.Options(LANDING_URL)
|
||||
.images(new Image("http://cdn.example.com/image1.jpg"), new Image("http://cdn.example.com/image2.jpg"))
|
||||
.priority(0.5)
|
||||
.changeFreq(ChangeFreq.WEEKLY)
|
||||
.build();
|
||||
wsg.addUrl(url);
|
||||
|
||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\" >\n" +
|
||||
" <url>\n" +
|
||||
" <loc>http://www.example.com/index.html</loc>\n" +
|
||||
" <changefreq>weekly</changefreq>\n" +
|
||||
" <priority>0.5</priority>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image1.jpg</image:loc>\n" +
|
||||
" </image:image>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image2.jpg</image:loc>\n" +
|
||||
" </image:image>\n" +
|
||||
" </url>\n" +
|
||||
"</urlset>";
|
||||
|
||||
String sitemap = writeSingleSiteMap(wsg);
|
||||
assertEquals(expected, sitemap);
|
||||
}
|
||||
|
||||
public void testImageOptions() throws Exception {
|
||||
wsg = new GoogleImageSitemapGenerator("http://www.example.com", dir);
|
||||
GoogleImageSitemapUrl url = new GoogleImageSitemapUrl.Options(LANDING_URL)
|
||||
.images(new Image.ImageBuilder("http://cdn.example.com/image1.jpg")
|
||||
.title("image1.jpg")
|
||||
.caption("An image of the number 1")
|
||||
.geoLocation("Pyongyang, North Korea")
|
||||
.license("http://cdn.example.com/licenses/imagelicense.txt")
|
||||
.build(),
|
||||
new Image.ImageBuilder("http://cdn.example.com/image2.jpg")
|
||||
.title("image2.jpg")
|
||||
.caption("An image of the number 2")
|
||||
.geoLocation("Pyongyang, North Korea")
|
||||
.license("http://cdn.example.com/licenses/imagelicense.txt")
|
||||
.build())
|
||||
.priority(0.5)
|
||||
.changeFreq(ChangeFreq.WEEKLY)
|
||||
.build();
|
||||
wsg.addUrl(url);
|
||||
|
||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\" >\n" +
|
||||
" <url>\n" +
|
||||
" <loc>http://www.example.com/index.html</loc>\n" +
|
||||
" <changefreq>weekly</changefreq>\n" +
|
||||
" <priority>0.5</priority>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image1.jpg</image:loc>\n" +
|
||||
" <image:caption>An image of the number 1</image:caption>\n" +
|
||||
" <image:title>image1.jpg</image:title>\n" +
|
||||
" <image:geo_location>Pyongyang, North Korea</image:geo_location>\n" +
|
||||
" <image:license>http://cdn.example.com/licenses/imagelicense.txt</image:license>\n" +
|
||||
" </image:image>\n" +
|
||||
" <image:image>\n" +
|
||||
" <image:loc>http://cdn.example.com/image2.jpg</image:loc>\n" +
|
||||
" <image:caption>An image of the number 2</image:caption>\n" +
|
||||
" <image:title>image2.jpg</image:title>\n" +
|
||||
" <image:geo_location>Pyongyang, North Korea</image:geo_location>\n" +
|
||||
" <image:license>http://cdn.example.com/licenses/imagelicense.txt</image:license>\n" +
|
||||
" </image:image>\n" +
|
||||
" </url>\n" +
|
||||
"</urlset>";
|
||||
|
||||
String sitemap = writeSingleSiteMap(wsg);
|
||||
assertEquals(expected, sitemap);
|
||||
}
|
||||
|
||||
public void testTooManyImages() throws Exception {
|
||||
wsg = new GoogleImageSitemapGenerator("http://www.example.com", dir);
|
||||
List<Image> images = new ArrayList<Image>();
|
||||
for(int i = 0; i <= 1000; i++) {
|
||||
images.add(new Image("http://cdn.example.com/image" + i + ".jpg"));
|
||||
}
|
||||
try {
|
||||
GoogleImageSitemapUrl url = new GoogleImageSitemapUrl.Options(LANDING_URL)
|
||||
.images(images)
|
||||
.priority(0.5)
|
||||
.changeFreq(ChangeFreq.WEEKLY)
|
||||
.build();
|
||||
fail("Too many images allowed");
|
||||
} catch (RuntimeException r) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String writeSingleSiteMap(GoogleImageSitemapGenerator wsg) {
|
||||
List<File> files = wsg.write();
|
||||
assertEquals("Too many files: " + files.toString(), 1, files.size());
|
||||
assertEquals("Sitemap misnamed", "sitemap.xml", files.get(0).getName());
|
||||
return TestUtil.slurpFileAndDelete(files.get(0));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue