sitemap_generator 2.2.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/Gemfile +9 -24
  2. data/Gemfile.lock +23 -58
  3. data/README.md +56 -75
  4. data/Rakefile +29 -117
  5. data/VERSION +1 -1
  6. data/lib/sitemap_generator.rb +24 -8
  7. data/lib/sitemap_generator/application.rb +31 -4
  8. data/lib/sitemap_generator/builder.rb +0 -6
  9. data/lib/sitemap_generator/builder/sitemap_file.rb +16 -6
  10. data/lib/sitemap_generator/builder/sitemap_index_file.rb +4 -3
  11. data/lib/sitemap_generator/builder/sitemap_index_url.rb +1 -1
  12. data/lib/sitemap_generator/builder/sitemap_url.rb +6 -8
  13. data/lib/sitemap_generator/core_ext.rb +3 -0
  14. data/lib/sitemap_generator/core_ext/big_decimal.rb +45 -0
  15. data/lib/sitemap_generator/core_ext/numeric.rb +48 -0
  16. data/lib/sitemap_generator/helpers/number_helper.rb +237 -0
  17. data/lib/sitemap_generator/interpreter.rb +1 -1
  18. data/lib/sitemap_generator/link_set.rb +39 -18
  19. data/lib/sitemap_generator/railtie.rb +2 -2
  20. data/lib/sitemap_generator/sitemap_namer.rb +1 -1
  21. data/lib/sitemap_generator/tasks.rb +53 -1
  22. data/lib/sitemap_generator/utilities.rb +107 -1
  23. data/lib/tasks/sitemap_generator_tasks.rake +1 -0
  24. data/spec/blueprint.rb +15 -0
  25. data/spec/files/sitemap.create.rb +12 -0
  26. data/spec/files/sitemap.deprecated.rb +13 -0
  27. data/spec/files/sitemap.groups.rb +37 -0
  28. data/spec/sitemap_generator/application_spec.rb +69 -0
  29. data/spec/sitemap_generator/builder/sitemap_file_spec.rb +77 -0
  30. data/spec/sitemap_generator/builder/sitemap_index_file_spec.rb +38 -0
  31. data/spec/sitemap_generator/builder/sitemap_index_url_spec.rb +16 -0
  32. data/spec/sitemap_generator/builder/sitemap_url_spec.rb +152 -0
  33. data/spec/sitemap_generator/core_ext/bigdecimal_spec.rb +20 -0
  34. data/spec/sitemap_generator/core_ext/numeric_spec.rb +43 -0
  35. data/spec/sitemap_generator/geo_sitemap_spec.rb +30 -0
  36. data/spec/sitemap_generator/helpers/number_helper_spec.rb +191 -0
  37. data/spec/sitemap_generator/interpreter_spec.rb +24 -0
  38. data/spec/sitemap_generator/link_set_spec.rb +606 -0
  39. data/spec/sitemap_generator/news_sitemap_spec.rb +42 -0
  40. data/spec/sitemap_generator/sitemap_generator_spec.rb +232 -0
  41. data/spec/sitemap_generator/sitemap_groups_spec.rb +133 -0
  42. data/spec/sitemap_generator/sitemap_location_spec.rb +124 -0
  43. data/spec/sitemap_generator/sitemap_namer_spec.rb +61 -0
  44. data/spec/sitemap_generator/templates_spec.rb +24 -0
  45. data/spec/sitemap_generator/utilities/existence_spec.rb +26 -0
  46. data/spec/sitemap_generator/utilities/hash_spec.rb +57 -0
  47. data/spec/sitemap_generator/utilities/rounding_spec.rb +31 -0
  48. data/spec/sitemap_generator/utilities_spec.rb +50 -0
  49. data/spec/sitemap_generator/video_sitemap_spec.rb +103 -0
  50. data/spec/spec_helper.rb +20 -0
  51. data/spec/support/file_macros.rb +39 -0
  52. data/spec/support/schemas/siteindex.xsd +73 -0
  53. data/spec/support/schemas/sitemap-geo.xsd +41 -0
  54. data/spec/support/schemas/sitemap-news.xsd +159 -0
  55. data/spec/support/schemas/sitemap-video.xsd +409 -0
  56. data/spec/support/schemas/sitemap.xsd +115 -0
  57. data/spec/support/xml_macros.rb +55 -0
  58. metadata +141 -122
  59. data/tasks/sitemap_generator_tasks.rake +0 -43
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SitemapGenerator::SitemapNamer' do
4
+
5
+ it "should generate file names" do
6
+ namer = SitemapGenerator::SitemapNamer.new(:sitemap)
7
+ namer.to_s.should == "sitemap1.xml.gz"
8
+ namer.next.to_s.should == "sitemap2.xml.gz"
9
+ namer.next.to_s.should == "sitemap3.xml.gz"
10
+ end
11
+
12
+ it "should set the file extension" do
13
+ namer = SitemapGenerator::SitemapNamer.new(:sitemap, :extension => '.xyz')
14
+ namer.to_s.should == "sitemap1.xyz"
15
+ namer.next.to_s.should == "sitemap2.xyz"
16
+ namer.next.to_s.should == "sitemap3.xyz"
17
+ end
18
+
19
+ it "should set the starting index" do
20
+ namer = SitemapGenerator::SitemapNamer.new(:sitemap, :start => 10)
21
+ namer.to_s.should == "sitemap10.xml.gz"
22
+ namer.next.to_s.should == "sitemap11.xml.gz"
23
+ namer.next.to_s.should == "sitemap12.xml.gz"
24
+ end
25
+
26
+ it "should accept a string name" do
27
+ namer = SitemapGenerator::SitemapNamer.new('abc-def')
28
+ namer.to_s.should == "abc-def1.xml.gz"
29
+ namer.next.to_s.should == "abc-def2.xml.gz"
30
+ namer.next.to_s.should == "abc-def3.xml.gz"
31
+ end
32
+
33
+ it "should return previous name" do
34
+ namer = SitemapGenerator::SitemapNamer.new(:sitemap)
35
+ namer.to_s.should == "sitemap1.xml.gz"
36
+ namer.next.to_s.should == "sitemap2.xml.gz"
37
+ namer.previous.to_s.should == "sitemap1.xml.gz"
38
+ namer.next.to_s.should == "sitemap2.xml.gz"
39
+ end
40
+
41
+ it "should raise if already at the start" do
42
+ namer = SitemapGenerator::SitemapNamer.new(:sitemap)
43
+ namer.to_s.should == "sitemap1.xml.gz"
44
+ lambda { namer.previous }.should raise_error
45
+ end
46
+
47
+ it "should handle names with underscores" do
48
+ namer = SitemapGenerator::SitemapNamer.new("sitemap1_")
49
+ namer.to_s.should == "sitemap1_1.xml.gz"
50
+ end
51
+ end
52
+
53
+ describe SitemapGenerator::SitemapIndexNamer do
54
+ it "should always return the same name" do
55
+ default = "sitemap_index.xml.gz"
56
+ namer = SitemapGenerator::SitemapIndexNamer.new(:sitemap_index)
57
+ namer.to_s.should == default
58
+ namer.next.to_s.should == default
59
+ namer.previous.to_s.should == default
60
+ end
61
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Templates class" do
4
+
5
+ it "should provide method access to each template" do
6
+ SitemapGenerator::Templates::FILES.each do |name, file|
7
+ SitemapGenerator.templates.send(name).should_not be(nil)
8
+ SitemapGenerator.templates.send(name).should == File.read(File.join(SitemapGenerator.root, 'templates', file))
9
+ end
10
+ end
11
+
12
+ describe "templates" do
13
+ before :each do
14
+ SitemapGenerator.templates.sitemap_sample = nil
15
+ File.expects(:read).returns('read file')
16
+ end
17
+
18
+ it "should only be read once" do
19
+ File.expects(:read).once
20
+ SitemapGenerator.templates.sitemap_sample
21
+ SitemapGenerator.templates.sitemap_sample
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ class EmptyTrue
4
+ def empty?() true; end
5
+ end
6
+
7
+ class EmptyFalse
8
+ def empty?() false; end
9
+ end
10
+
11
+ BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ]
12
+ NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ]
13
+
14
+ describe Object do
15
+ let(:utils) { SitemapGenerator::Utilities }
16
+
17
+ it "should define blankness" do
18
+ BLANK.each { |v| utils.blank?(v).should be_true }
19
+ NOT.each { |v| utils.blank?(v).should be_false }
20
+ end
21
+
22
+ it "should define presence" do
23
+ BLANK.each { |v| utils.present?(v).should be_false }
24
+ NOT.each { |v| utils.present?(v).should be_true }
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe SitemapGenerator::Utilities do
4
+ let(:utils) { SitemapGenerator::Utilities }
5
+
6
+ describe "assert_valid_keys" do
7
+ it "should raise" do
8
+ lambda do
9
+ utils.assert_valid_keys({ :failore => "stuff", :funny => "business" }, [ :failure, :funny])
10
+ utils.assert_valid_keys({ :failore => "stuff", :funny => "business" }, :failure, :funny)
11
+ end.should raise_error(ArgumentError, "Unknown key(s): failore")
12
+ end
13
+
14
+ it "should not raise" do
15
+ lambda do
16
+ utils.assert_valid_keys({ :failure => "stuff", :funny => "business" }, [ :failure, :funny ])
17
+ utils.assert_valid_keys({ :failure => "stuff", :funny => "business" }, :failure, :funny)
18
+ end.should_not raise_error
19
+ end
20
+ end
21
+
22
+ describe "keys" do
23
+ before :each do
24
+ @strings = { 'a' => 1, 'b' => 2 }
25
+ @symbols = { :a => 1, :b => 2 }
26
+ @mixed = { :a => 1, 'b' => 2 }
27
+ @fixnums = { 0 => 1, 1 => 2 }
28
+ if RUBY_VERSION < '1.9.0'
29
+ @illegal_symbols = { "\0" => 1, "" => 2, [] => 3 }
30
+ else
31
+ @illegal_symbols = { [] => 3 }
32
+ end
33
+ end
34
+
35
+ it "should symbolize_keys" do
36
+ utils.symbolize_keys(@symbols).should == @symbols
37
+ utils.symbolize_keys(@strings).should == @symbols
38
+ utils.symbolize_keys(@mixed).should == @symbols
39
+ end
40
+
41
+ it "should symbolize_keys!" do
42
+ utils.symbolize_keys!(@symbols.dup).should == @symbols
43
+ utils.symbolize_keys!(@strings.dup).should == @symbols
44
+ utils.symbolize_keys!(@mixed.dup).should == @symbols
45
+ end
46
+
47
+ it "should symbolize_keys_preserves_keys_that_cant_be_symbolized" do
48
+ utils.symbolize_keys(@illegal_symbols).should == @illegal_symbols
49
+ utils.symbolize_keys!(@illegal_symbols.dup).should == @illegal_symbols
50
+ end
51
+
52
+ it "should symbolize_keys_preserves_fixnum_keys" do
53
+ utils.symbolize_keys(@fixnums).should == @fixnums
54
+ utils.symbolize_keys!(@fixnums.dup).should == @fixnums
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe SitemapGenerator::Utilities do
4
+ describe "rounding" do
5
+ let(:utils) { SitemapGenerator::Utilities }
6
+
7
+ it "should round for positive number" do
8
+ utils.round(1.4) .should == 1
9
+ utils.round(1.6) .should == 2
10
+ utils.round(1.6, 0) .should == 2
11
+ utils.round(1.4, 1) .should == 1.4
12
+ utils.round(1.4, 3) .should == 1.4
13
+ utils.round(1.45, 1) .should == 1.5
14
+ utils.round(1.445, 2).should == 1.45
15
+ # Demonstrates a bug in the round method
16
+ # utils.round(9.995, 2).should == 10
17
+ end
18
+
19
+ it "should round for negative number" do
20
+ utils.round(-1.4) .should == -1
21
+ utils.round(-1.6) .should == -2
22
+ utils.round(-1.4, 1) .should == -1.4
23
+ utils.round(-1.45, 1).should == -1.5
24
+ end
25
+
26
+ it "should round with negative precision" do
27
+ utils.round(123456.0, -1).should == 123460.0
28
+ utils.round(123456.0, -2).should == 123500.0
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe SitemapGenerator::Utilities do
4
+
5
+ describe "assert_valid_keys" do
6
+ it "should raise error on invalid keys" do
7
+ lambda {
8
+ SitemapGenerator::Utilities.assert_valid_keys({ :name => "Rob", :years => "28" }, :name, :age)
9
+ }.should raise_exception(ArgumentError)
10
+ lambda {
11
+ SitemapGenerator::Utilities.assert_valid_keys({ :name => "Rob", :age => "28" }, "name", "age")
12
+ }.should raise_exception(ArgumentError)
13
+ end
14
+
15
+ it "should not raise error on valid keys" do
16
+ lambda {
17
+ SitemapGenerator::Utilities.assert_valid_keys({ :name => "Rob", :age => "28" }, :name, :age)
18
+ }.should_not raise_exception
19
+
20
+ lambda {
21
+ SitemapGenerator::Utilities.assert_valid_keys({ :name => "Rob" }, :name, :age)
22
+ }.should_not raise_exception
23
+ end
24
+ end
25
+
26
+ describe "titleize" do
27
+ it "should titleize words and replace underscores" do
28
+ SitemapGenerator::Utilities.titleize('google').should == 'Google'
29
+ SitemapGenerator::Utilities.titleize('amy_and_jon').should == 'Amy And Jon'
30
+ end
31
+ end
32
+
33
+ describe "truthy?" do
34
+ it "should be truthy" do
35
+ ['1', 1, 't', 'true', true].each do |value|
36
+ SitemapGenerator::Utilities.truthy?(value).should be_true
37
+ end
38
+ SitemapGenerator::Utilities.truthy?(nil).should be_false
39
+ end
40
+ end
41
+
42
+ describe "falsy?" do
43
+ it "should be falsy" do
44
+ ['0', 0, 'f', 'false', false].each do |value|
45
+ SitemapGenerator::Utilities.falsy?(value).should be_true
46
+ end
47
+ SitemapGenerator::Utilities.falsy?(nil).should be_false
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe "SitemapGenerator" do
4
+ let(:url_options) do
5
+ {
6
+ :host => 'http://example.com',
7
+ :path => 'cool_video.html'
8
+ }
9
+ end
10
+
11
+ let(:video_options) do
12
+ {
13
+ :thumbnail_loc => 'http://example.com/video1_thumbnail.png',
14
+ :title => 'Cool Video',
15
+ :content_loc => 'http://example.com/cool_video.mpg',
16
+ :player_loc => 'http://example.com/cool_video_player.swf',
17
+ :gallery_loc => 'http://example.com/cool_video_gallery',
18
+ :gallery_title => 'Gallery Title',
19
+ :allow_embed => true,
20
+ :autoplay => 'id=123',
21
+ :description => 'An new perspective in cool video technology',
22
+ :tags => %w(tag1 tag2 tag3),
23
+ :category => 'cat1',
24
+ :uploader => 'sokrates',
25
+ :uploader_info => 'http://sokrates.example.com',
26
+ :expiration_date => Time.at(0),
27
+ :publication_date => Time.at(0),
28
+ :family_friendly => true,
29
+ :view_count => 123,
30
+ :duration => 456,
31
+ :rating => 0.499999999
32
+ }
33
+ end
34
+
35
+ # Return XML for the <URL> element.
36
+ def video_xml(video_options)
37
+ SitemapGenerator::Builder::SitemapUrl.new(url_options[:path], {
38
+ :host => url_options[:host],
39
+ :video => video_options
40
+ }).to_xml
41
+ end
42
+
43
+ # Return a Nokogiri document from the XML. The root of the document is the <URL> element.
44
+ def video_doc(xml)
45
+ Nokogiri::XML.parse("<root xmlns:video='http://www.google.com/schemas/sitemap-video/1.1'>#{xml}</root>")
46
+ end
47
+
48
+ # Validate the contents of the video element
49
+ def validate_video_element(video_doc, video_options)
50
+ video_doc.at_xpath('video:thumbnail_loc').text.should == video_options[:thumbnail_loc]
51
+ video_doc.at_xpath("video:thumbnail_loc").text.should == video_options[:thumbnail_loc]
52
+ video_doc.at_xpath("video:gallery_loc").text.should == video_options[:gallery_loc]
53
+ video_doc.at_xpath("video:gallery_loc").attribute('title').text.should == video_options[:gallery_title]
54
+ video_doc.at_xpath("video:title").text.should == video_options[:title]
55
+ video_doc.at_xpath("video:view_count").text.should == video_options[:view_count].to_s
56
+ video_doc.at_xpath("video:duration").text.should == video_options[:duration].to_s
57
+ video_doc.at_xpath("video:rating").text.should == ('%0.1f' % video_options[:rating])
58
+ video_doc.at_xpath("video:content_loc").text.should == video_options[:content_loc]
59
+ video_doc.at_xpath("video:category").text.should == video_options[:category]
60
+ video_doc.xpath("video:tag").collect(&:text).should == video_options[:tags]
61
+ video_doc.at_xpath("video:expiration_date").text.should == video_options[:expiration_date].iso8601
62
+ video_doc.at_xpath("video:publication_date").text.should == video_options[:publication_date].iso8601
63
+ video_doc.at_xpath("video:player_loc").text.should == video_options[:player_loc]
64
+ video_doc.at_xpath("video:player_loc").attribute('allow_embed').text.should == (video_options[:allow_embed] ? 'yes' : 'no')
65
+ video_doc.at_xpath("video:player_loc").attribute('autoplay').text.should == video_options[:autoplay]
66
+ video_doc.at_xpath("video:uploader").text.should == video_options[:uploader]
67
+ video_doc.at_xpath("video:uploader").attribute("info").text.should == video_options[:uploader_info]
68
+ xml_fragment_should_validate_against_schema(video_doc, 'http://www.google.com/schemas/sitemap-video/1.1', 'sitemap-video')
69
+ end
70
+
71
+ it "should add a valid video sitemap element" do
72
+ xml = video_xml(video_options)
73
+ doc = video_doc(xml)
74
+ doc.at_xpath("//url/loc").text.should == File.join(url_options[:host], url_options[:path])
75
+ validate_video_element(doc.at_xpath('//url/video:video'), video_options)
76
+ end
77
+
78
+ it "should support multiple video elements" do
79
+ xml = video_xml([video_options, video_options])
80
+ doc = video_doc(xml)
81
+ doc.at_xpath("//url/loc").text.should == File.join(url_options[:host], url_options[:path])
82
+ doc.xpath('//url/video:video').count.should == 2
83
+ doc.xpath('//url/video:video').each do |video|
84
+ validate_video_element(video, video_options)
85
+ end
86
+ end
87
+
88
+ it "should default allow_embed to 'yes'" do
89
+ xml = video_xml(video_options.merge(:allow_embed => nil))
90
+ doc = video_doc(xml)
91
+ doc.at_xpath("//url/video:video/video:player_loc").attribute('allow_embed').text.should == 'yes'
92
+ end
93
+
94
+ it "should not include optional elements if they are not passed" do
95
+ optional = [:player_loc, :content_loc, :category, :tags, :tag, :uploader, :gallery_loc, :family_friendly, :publication_date, :expiration_date, :view_count, :rating, :duration]
96
+ required_options = video_options.delete_if { |k,v| optional.include?(k) }
97
+ xml = video_xml(required_options)
98
+ doc = video_doc(xml)
99
+ optional.each do |element|
100
+ doc.at_xpath("//url/video:video/video:#{element}").should be_nil
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,20 @@
1
+ require "bundler/setup"
2
+ Bundler.require
3
+ require 'rspec/autorun'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
8
+
9
+ SitemapGenerator.verbose = false
10
+
11
+ RSpec.configure do |config|
12
+ config.mock_with :mocha
13
+ config.include(FileMacros)
14
+ config.include(XmlMacros)
15
+
16
+ # Pass :focus option to +describe+ or +it+ to run that spec only
17
+ config.treat_symbols_as_metadata_keys_with_true_values = true
18
+ config.filter_run :focus => true
19
+ config.run_all_when_everything_filtered = true
20
+ end
@@ -0,0 +1,39 @@
1
+ module FileMacros
2
+ module ExampleMethods
3
+
4
+ def files_should_be_identical(first, second)
5
+ identical_files?(first, second).should be(true)
6
+ end
7
+
8
+ def files_should_not_be_identical(first, second)
9
+ identical_files?(first, second).should be(false)
10
+ end
11
+
12
+ def file_should_exist(file)
13
+ File.exists?(file).should be(true), "File #{file} should exist"
14
+ end
15
+
16
+ def directory_should_exist(dir)
17
+ File.exists?(dir).should be(true), "Directory #{dir} should exist"
18
+ File.directory?(dir).should be(true), "#{dir} should be a directory"
19
+ end
20
+
21
+ def directory_should_not_exist(dir)
22
+ File.exists?(dir).should be(false), "Directory #{dir} should not exist"
23
+ end
24
+
25
+ def file_should_not_exist(file)
26
+ File.exists?(file).should be(false), "File #{file} should not exist"
27
+ end
28
+
29
+ def identical_files?(first, second)
30
+ file_should_exist(first)
31
+ file_should_exist(second)
32
+ open(second, 'r').read.should == open(first, 'r').read
33
+ end
34
+ end
35
+
36
+ def self.included(receiver)
37
+ receiver.send :include, ExampleMethods
38
+ end
39
+ end
@@ -0,0 +1,73 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
4
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
5
+ elementFormDefault="qualified">
6
+ <xsd:annotation>
7
+ <xsd:documentation>
8
+ XML Schema for Sitemap index files.
9
+ Last Modifed 2009-04-08
10
+ </xsd:documentation>
11
+ </xsd:annotation>
12
+
13
+ <xsd:element name="sitemapindex">
14
+ <xsd:annotation>
15
+ <xsd:documentation>
16
+ Container for a set of up to 50,000 sitemap URLs.
17
+ This is the root element of the XML file.
18
+ </xsd:documentation>
19
+ </xsd:annotation>
20
+ <xsd:complexType>
21
+ <xsd:sequence>
22
+ <xsd:element name="sitemap" type="tSitemap" maxOccurs="unbounded"/>
23
+ </xsd:sequence>
24
+ </xsd:complexType>
25
+ </xsd:element>
26
+
27
+ <xsd:complexType name="tSitemap">
28
+ <xsd:annotation>
29
+ <xsd:documentation>
30
+ Container for the data needed to describe a sitemap.
31
+ </xsd:documentation>
32
+ </xsd:annotation>
33
+ <xsd:all>
34
+ <xsd:element name="loc" type="tLocSitemap"/>
35
+ <xsd:element name="lastmod" type="tLastmodSitemap" minOccurs="0"/>
36
+ </xsd:all>
37
+ </xsd:complexType>
38
+
39
+ <xsd:simpleType name="tLocSitemap">
40
+ <xsd:annotation>
41
+ <xsd:documentation>
42
+ REQUIRED: The location URI of a sitemap.
43
+ The URI must conform to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt).
44
+ </xsd:documentation>
45
+ </xsd:annotation>
46
+ <xsd:restriction base="xsd:anyURI">
47
+ <xsd:minLength value="12"/>
48
+ <xsd:maxLength value="2048"/>
49
+ </xsd:restriction>
50
+ </xsd:simpleType>
51
+
52
+ <xsd:simpleType name="tLastmodSitemap">
53
+ <xsd:annotation>
54
+ <xsd:documentation>
55
+ OPTIONAL: The date the document was last modified. The date must conform
56
+ to the W3C DATETIME format (http://www.w3.org/TR/NOTE-datetime).
57
+ Example: 2005-05-10
58
+ Lastmod may also contain a timestamp.
59
+ Example: 2005-05-10T17:33:30+08:00
60
+ </xsd:documentation>
61
+ </xsd:annotation>
62
+ <xsd:union>
63
+ <xsd:simpleType>
64
+ <xsd:restriction base="xsd:date"/>
65
+ </xsd:simpleType>
66
+ <xsd:simpleType>
67
+ <xsd:restriction base="xsd:dateTime"/>
68
+ </xsd:simpleType>
69
+ </xsd:union>
70
+ </xsd:simpleType>
71
+
72
+
73
+ </xsd:schema>