]> gitweb.michael.orlitzky.com - dead/htsn-import.git/commitdiff
Add support for the new Detailed_Weather elements.
authorMichael Orlitzky <michael@orlitzky.com>
Sat, 5 Jul 2014 17:34:09 +0000 (13:34 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Sat, 5 Jul 2014 17:34:09 +0000 (13:34 -0400)
Add another test case for the weather.
Update the TODO.

doc/TODO
src/TSN/XML/Weather.hs
test/shell/import-duplicates.test
test/xml/weatherxml-detailed.xml [new file with mode: 0644]

index 66f8d3a4e82fb534fe899be96acd6737ba264a12..9413031f102bfb8850a01b35bc07ba1ccb8b4481 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -4,7 +4,8 @@
 2. Write a test for test/xml/Odds_XML-long-import.xml once it no
    longer takes 10 minutes to import (Postgres only?).
 
-3. Add support the the second type of weatherxml (see man page).
+3. Return ImportUnsupported for the second type of weatherxml (see man
+   page).
 
 4. We have DTDs but no sample XML for the following SportInfo types,
    which have therefore been left unimplmented for now:
index 6df3ce37615cfa48ba28cc028fb355a90dcbbb1d..c2eee4a6c739625d9ec19f114fadae12f854072b 100644 (file)
@@ -16,6 +16,7 @@ module TSN.XML.Weather (
   weather_tests,
   -- * WARNING: these are private but exported to silence warnings
   WeatherConstructor(..),
+  WeatherDetailedWeatherListingItemConstructor(..),
   WeatherForecastConstructor(..),
   WeatherForecastListingConstructor(..) )
 where
@@ -41,7 +42,8 @@ import Test.Tasty ( TestTree, testGroup )
 import Test.Tasty.HUnit ( (@?=), testCase )
 import Text.XML.HXT.Core (
   PU,
-  xp7Tuple,
+  xp8Tuple,
+  xp9Tuple,
   xpAttr,
   xpElem,
   xpInt,
@@ -49,13 +51,14 @@ import Text.XML.HXT.Core (
   xpOption,
   xpPair,
   xpText,
+  xpTriple,
   xpWrap )
 
 -- Local imports.
 import TSN.Codegen (
   tsn_codegen_config )
 import TSN.DbImport ( DbImport(..), ImportResult(..), run_dbmigrate )
-import TSN.Picklers ( xp_gamedate, xp_time_stamp )
+import TSN.Picklers ( xp_datetime, xp_gamedate, xp_time_stamp )
 import TSN.XmlImport ( XmlImport(..), XmlImportFk(..) )
 import Xml (
   Child(..),
@@ -183,10 +186,111 @@ instance FromXmlFk WeatherForecastXml where
 --
 instance XmlImportFk WeatherForecastXml
 
+-- * WeatherDetailedWeatherXml
+
+-- | XML Representation of a \<Detailed_Weather\>, which just contains
+--   a bunch iof \<DW_Listing\>s. There is no associated database type
+--   since these don't really contain any information.
+--
+data WeatherDetailedWeatherXml =
+  WeatherDetailedWeatherXml {
+    xml_detailed_listings :: [WeatherDetailedWeatherListingXml] }
+  deriving (Eq, Show)
+
+
+-- * WeatherDetailedWeatherXml
+
+-- | XML Representation of a \<DW_Listing\>. The sport and sport code
+--   come as attributes, but then these just contain a bunch of
+--   \<Item\>s. There is no associated database type since these don't
+--   contain much information. The sport we already know from the
+--   \<message\>, while the sport code is ignored since it's already
+--   present in each \<Item\>s.
+--
+data WeatherDetailedWeatherListingXml =
+  WeatherDetailedWeatherListingXml {
+    xml_dtl_listing_sport :: String,
+    xml_dtl_listing_sport_code :: String,
+    xml_items :: [WeatherDetailedWeatherListingItemXml] }
+  deriving (Eq, Show)
+
+-- * WeatherDetailedWeatherListingItem / WeatherDetailedWeatherListingItemXml
+
+-- | Database representation of a detailed weather item. The away/home
+--   teams don't use the representation in "TSN.Team" because all
+--   we're given is a name, and a team id is required for "TSN.Team".
+--
+--   We also drop the sport name, because it's given in the parent
+--   'Weather'.
+--
+data WeatherDetailedWeatherListingItem =
+  WeatherDetailedWeatherListingItem {
+    db_dtl_weather_id :: DefaultKey Weather, -- ^ Avoid name collision by
+                                             --   using \"dtl\" prefix.
+    db_sport_code :: String,
+    db_game_id :: Int,
+    db_dtl_game_date :: UTCTime, -- ^ Avoid name clash with \"dtl\" prefix
+    db_away_team :: String,
+    db_home_team :: String,
+    db_weather_type :: Int,
+    db_description :: String,
+    db_temp_adjust :: String,
+    db_temperature :: Int }
+
+
+-- | XML representation of a detailed weather item. Same as the
+--   database representation, only without the foreign key and the
+--   sport name that comes from the containing listing.
+data WeatherDetailedWeatherListingItemXml =
+  WeatherDetailedWeatherListingItemXml {
+    xml_sport_code :: String,
+    xml_game_id :: Int,
+    xml_dtl_game_date :: UTCTime,
+    xml_away_team :: String,
+    xml_home_team :: String,
+    xml_weather_type :: Int,
+    xml_description :: String,
+    xml_temp_adjust :: String,
+    xml_temperature :: Int }
+  deriving (Eq, Show)
+
+
+instance ToDb WeatherDetailedWeatherListingItemXml where
+  -- | Our database analogue is a 'WeatherDetailedWeatherListingItem'.
+  type Db WeatherDetailedWeatherListingItemXml =
+    WeatherDetailedWeatherListingItem
+
+instance Child WeatherDetailedWeatherListingItemXml where
+  -- | We skip two levels of containers and say that the items belong
+  --   to the top-level 'Weather'.
+  type Parent WeatherDetailedWeatherListingItemXml = Weather
+
+instance FromXmlFk WeatherDetailedWeatherListingItemXml where
+  -- | To convert from the XML to database representation, we simply
+  --   add the foreign key (to Weather) and copy the rest of the fields.
+  from_xml_fk fk WeatherDetailedWeatherListingItemXml{..} =
+    WeatherDetailedWeatherListingItem {
+      db_dtl_weather_id = fk,
+      db_sport_code = xml_sport_code,
+      db_game_id = xml_game_id,
+      db_dtl_game_date = xml_dtl_game_date,
+      db_away_team = xml_away_team,
+      db_home_team = xml_home_team,
+      db_weather_type = xml_weather_type,
+      db_description = xml_description,
+      db_temp_adjust = xml_temp_adjust,
+      db_temperature = xml_temperature }
+
+-- | This allows us to insert the XML representation directly without
+--   having to do the manual XML -\> DB conversion.
+--
+instance XmlImportFk WeatherDetailedWeatherListingItemXml
 
 -- * Weather/Message
 
--- | The database representation of a weather message.
+-- | The database representation of a weather message. We don't
+-- contain the forecasts or the detailed weather since those are
+-- foreigned-keyed to us.
 --
 data Weather =
   Weather {
@@ -206,6 +310,7 @@ data Message =
     xml_sport :: String,
     xml_title :: String,
     xml_forecasts :: [WeatherForecastXml],
+    xml_detailed_weather :: Maybe WeatherDetailedWeatherXml,
     xml_time_stamp :: UTCTime }
   deriving (Eq, Show)
 
@@ -232,7 +337,7 @@ instance XmlImport Message
 
 
 --
--- Database stuff
+-- Database stuff
 --
 
 mkPersist tsn_codegen_config [groundhog|
@@ -263,6 +368,19 @@ mkPersist tsn_codegen_config [groundhog|
           reference:
             onDelete: cascade
 
+# We rename the two fields that needed a "dtl" prefix to avoid a name clash.
+- entity: WeatherDetailedWeatherListingItem
+  dbName: weather_detailed_items
+  constructors:
+    - name: WeatherDetailedWeatherListingItem
+      fields:
+        - name: db_dtl_weather_id
+          dbName: weather_id
+          reference:
+            onDelete: cascade
+        - name: db_dtl_game_date
+          dbName: game_date
+
 |]
 
 
@@ -272,6 +390,7 @@ instance DbImport Message where
       migrate (undefined :: Weather)
       migrate (undefined :: WeatherForecast)
       migrate (undefined :: WeatherForecastListing)
+      migrate (undefined :: WeatherDetailedWeatherListingItem)
 
   dbimport m = do
     -- First we insert the top-level weather record.
@@ -297,9 +416,9 @@ instance DbImport Message where
     return ImportSucceeded
 
 
----
---- Pickling
----
+--
+-- * Pickling
+--
 
 -- | Pickler to convert a 'WeatherForecastListingXml' to/from XML.
 --
@@ -345,19 +464,73 @@ pickle_forecast =
 
 
 
+-- | (Un)pickle a 'WeatherDetailedWeatherListingItemXml'.
+--
+pickle_item :: PU WeatherDetailedWeatherListingItemXml
+pickle_item =
+  xpElem "Item" $
+    xpWrap (from_tuple, to_tuple) $
+    xp9Tuple (xpElem "Sportcode" xpText)
+             (xpElem "GameID" xpInt)
+             (xpElem "Gamedate" xp_datetime)
+             (xpElem "AwayTeam" xpText)
+             (xpElem "HomeTeam" xpText)
+             (xpElem "WeatherType" xpInt)
+             (xpElem "Description" xpText)
+             (xpElem "TempAdjust" xpText)
+             (xpElem "Temperature" xpInt)
+  where
+    from_tuple = uncurryN WeatherDetailedWeatherListingItemXml
+    to_tuple w = (xml_sport_code w,
+                  xml_game_id w,
+                  xml_dtl_game_date w,
+                  xml_away_team w,
+                  xml_home_team w,
+                  xml_weather_type w,
+                  xml_description w,
+                  xml_temp_adjust w,
+                  xml_temperature w)
+
+
+-- | (Un)pickle a 'WeatherDetailedWeatherListingXml'.
+--
+pickle_dw_listing :: PU WeatherDetailedWeatherListingXml
+pickle_dw_listing =
+  xpElem "DW_Listing" $
+    xpWrap (from_tuple, to_tuple) $
+    xpTriple (xpAttr "SportCode" xpText)
+             (xpAttr "Sport" xpText)
+             (xpList pickle_item)
+  where
+    from_tuple = uncurryN WeatherDetailedWeatherListingXml
+    to_tuple w = (xml_dtl_listing_sport w,
+                  xml_dtl_listing_sport_code w,
+                  xml_items w)
+
+
+-- | (Un)pickle a 'WeatherDetailedWeatherXml'
+--
+pickle_detailed_weather :: PU WeatherDetailedWeatherXml
+pickle_detailed_weather =
+  xpElem "Detailed_Weather" $
+    xpWrap (WeatherDetailedWeatherXml, xml_detailed_listings)
+    (xpList pickle_dw_listing)
+
+
 -- | Pickler to convert a 'Message' to/from XML.
 --
 pickle_message :: PU Message
 pickle_message =
   xpElem "message" $
     xpWrap (from_tuple, to_tuple) $
-      xp7Tuple
+      xp8Tuple
         (xpElem "XML_File_ID" xpInt)
         (xpElem "heading" xpText)
         (xpElem "category" xpText)
         (xpElem "sport" xpText)
         (xpElem "title" xpText)
         (xpList pickle_forecast)
+        (xpOption pickle_detailed_weather)
         (xpElem "time_stamp" xp_time_stamp)
   where
     from_tuple = uncurryN Message
@@ -367,12 +540,13 @@ pickle_message =
                             xml_sport,
                             xml_title,
                             xml_forecasts,
+                            xml_detailed_weather,
                             xml_time_stamp)
 
+
 --
--- Tasty tests
+-- Tasty tests
 --
-
 weather_tests :: TestTree
 weather_tests =
   testGroup
@@ -387,45 +561,61 @@ weather_tests =
 --   test does not mean that unpickling succeeded.
 --
 test_pickle_of_unpickle_is_identity :: TestTree
-test_pickle_of_unpickle_is_identity =
-  testCase "pickle composed with unpickle is the identity" $ do
-    let path = "test/xml/weatherxml.xml"
-    (expected, actual) <- pickle_unpickle pickle_message path
-    actual @?= expected
+test_pickle_of_unpickle_is_identity = testGroup "pickle-unpickle tests"
+  [ check "pickle composed with unpickle is the identity"
+          "test/xml/weatherxml.xml",
+
+    check "pickle composed with unpickle is the identity (detailed)"
+          "test/xml/weatherxml-detailed.xml" ]
+  where
+    check desc path = testCase desc $ do
+      (expected, actual) <- pickle_unpickle pickle_message path
+      actual @?= expected
 
 
 -- | Make sure we can actually unpickle these things.
 --
 test_unpickle_succeeds :: TestTree
-test_unpickle_succeeds =
-  testCase "unpickling succeeds" $ do
-    let path = "test/xml/weatherxml.xml"
-    actual <- unpickleable path pickle_message
-    let expected = True
-    actual @?= expected
+test_unpickle_succeeds = testGroup "unpickle tests"
+  [ check "unpickling succeeds"
+          "test/xml/weatherxml.xml",
+    check "unpickling succeeds (detailed)"
+          "test/xml/weatherxml-detailed.xml" ]
+  where
+    check desc path = testCase desc $ do
+      actual <- unpickleable path pickle_message
+      let expected = True
+      actual @?= expected
 
 
 -- | Make sure everything gets deleted when we delete the top-level
 --   record.
 --
 test_on_delete_cascade :: TestTree
-test_on_delete_cascade =
-  testCase "deleting weather deletes its children" $ do
-    let path = "test/xml/weatherxml.xml"
-    weather <- unsafe_unpickle path pickle_message
-    let a = undefined :: Weather
-    let b = undefined :: WeatherForecast
-    let c = undefined :: WeatherForecastListing
-    actual <- withSqliteConn ":memory:" $ runDbConn $ do
-                runMigration silentMigrationLogger $ do
-                  migrate a
-                  migrate b
-                  migrate c
-                _ <- dbimport weather
-                deleteAll a
-                count_a <- countAll a
-                count_b <- countAll b
-                count_c <- countAll c
-                return $ count_a + count_b + count_c
-    let expected = 0
-    actual @?= expected
+test_on_delete_cascade = testGroup "cascading delete tests"
+  [ check "deleting weather deletes its children"
+          "test/xml/weatherxml.xml",
+    check "deleting weather deletes its children (detailed)"
+          "test/xml/weatherxml-detailed.xml" ]
+  where
+    check desc path = testCase desc $ do
+      weather <- unsafe_unpickle path pickle_message
+      let a = undefined :: Weather
+      let b = undefined :: WeatherForecast
+      let c = undefined :: WeatherForecastListing
+      let d = undefined :: WeatherDetailedWeatherListingItem
+      actual <- withSqliteConn ":memory:" $ runDbConn $ do
+                  runMigration silentMigrationLogger $ do
+                    migrate a
+                    migrate b
+                    migrate c
+                    migrate d
+                  _ <- dbimport weather
+                  deleteAll a
+                  count_a <- countAll a
+                  count_b <- countAll b
+                  count_c <- countAll c
+                  count_d <- countAll d
+                  return $ count_a + count_b + count_c + count_d
+      let expected = 0
+      actual @?= expected
index 1cefc531fa42234f00f9f11f3987975c4492aa4e..247a99681601be4c3601176a4ea70788423fce92 100644 (file)
@@ -15,15 +15,15 @@ rm -f shelltest.sqlite3
 # Heartbeat.xml that doesn't really count.
 find ./test/xml -maxdepth 1 -name '*.xml' | wc -l
 >>>
-21
+22
 >>>= 0
 
 # Run the imports again; we should get complaints about the duplicate
-# xml_file_ids. There are 2 errors for each violation, so we expect 2*20
+# xml_file_ids. There are 2 errors for each violation, so we expect 2*21
 # occurrences of the string 'ERROR'.
 ./dist/build/htsn-import/htsn-import -c 'shelltest.sqlite3' test/xml/*.xml 2>&1 | grep ERROR | wc -l
 >>>
-40
+42
 >>>= 0
 
 # Finally, clean up after ourselves.
diff --git a/test/xml/weatherxml-detailed.xml b/test/xml/weatherxml-detailed.xml
new file mode 100644 (file)
index 0000000..6c86f4d
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no" ?>\r<!DOCTYPE message PUBLIC "-//TSN//DTD Weather 1.0/EN" "weatherxml.dtd">\r<message>\r<XML_File_ID>21379214</XML_File_ID>\r<heading>AAW%BBWEATHER</heading>\r<category>Weather</category>\r<sport>MLB</sport>\r<title>Major League Baseball Weather from The Sports Network</title>\r<forecast gamedate="Friday, July 4th">\r<league name="National League">\r<listing>\r<teams>Chicago Cubs at Washington Nationals, 11:05 a.m.</teams>\r<weather>Mostly cloudy. Winds blowing in from left field at 10-15 m.p.h.  Game-time temperature: Around 75.</weather>\r</listing>\r<listing>\r<teams>Philadelphia Phillies at Pittsburgh Pirates, 5:05 p.m.</teams>\r<weather>Sunny. Winds blowing out to right field at 10-15 m.p.h.  Game-time temperature: Near 75.</weather>\r</listing>\r<listing>\r<teams>San Francisco Giants at San Diego Padres, 6:40 p.m.</teams>\r<weather>Partly cloudy. Winds blowing out to right field at 5-10 m.p.h.  Game-time temperature: Around 75.</weather>\r</listing>\r<listing>\r<teams>Milwaukee Brewers at Cincinnati Reds, 7:10 p.m.</teams>\r<weather>Sunny. Winds blowing out to right field at 5-10 m.p.h.  Game-time temperature: Near 75.</weather>\r</listing>\r<listing>\r<teams>Miami Marlins at St. Louis Cardinals, 7:15 p.m.</teams>\r<weather>Sunny. Winds blowing in from right field at 5-10 m.p.h.  Game-time temperature: Near 80.</weather>\r</listing>\r<listing>\r<teams>Arizona Diamondbacks at Atlanta Braves, 7:35 p.m.</teams>\r<weather>Mostly sunny. Winds blowing in from left field at 5-10 m.p.h.  Game-time temperature: Around 80.</weather>\r</listing>\r<listing>\r<teams>Los Angeles Dodgers at Colorado Rockies, 8:10 p.m.</teams>\r<weather>Partly cloudy with a 30-percent chance of rain. Winds blowing out to right  field at 5-10 m.p.h.  Game-time temperature: Around 80.</weather>\r</listing>\r</league>\r<league name="Interleague">\r<listing>\r<teams>Texas Rangers at New York Mets, 7:10 p.m.</teams>\r<weather>Partly cloudy. Winds blowing in from left field at 10-20 m.p.h.  Game-time temperature: Near 75.</weather>\r</listing>\r</league>\r<league name="American League">\r<listing>\r<teams>Baltimore Orioles at Boston Red Sox, 1:35 p.m.</teams>\r<weather>Cloudy with a 90-percent chance of rain. Winds blowing in from left field at  10-15 m.p.h.  Game-time temperature: Around 75.</weather>\r</listing>\r<listing>\r<teams>New York Yankees at Minnesota Twins, 3:10 p.m.</teams>\r<weather>Partly cloudy. Winds blowing in from right field at 10-15 m.p.h.  Game-time temperature: Around 75.</weather>\r</listing>\r<listing>\r<teams>Toronto Blue Jays at Oakland Athletics, 4:05 p.m.</teams>\r<weather>Sunny. Winds blowing out to center field at 10-15 m.p.h.  Game-time temperature: Around 65.</weather>\r</listing>\r<listing>\r<teams>Tampa Bay Rays at Detroit Tigers, 7:08 p.m.</teams>\r<weather>Sunny. Winds blowing out to right field at 5-10 m.p.h.  Game-time temperature: Around 75.</weather>\r</listing>\r<listing>\r<teams>Kansas City Royals at Cleveland Indians, 7:05 p.m.</teams>\r<weather>Sunny. Winds blowing in from left field at 5-10 m.p.h.  Game-time temperature: Near 70.</weather>\r</listing>\r<listing>\r<teams>Seattle Mariners at Chicago White Sox, 7:10 p.m.</teams>\r<weather>Sunny. Winds blowing in from center field at 5-10 m.p.h.  Game-time temperature: Around 60.</weather>\r</listing>\r<listing>\r<teams>Houston Astros at LA Angels of Anaheim, 9:05 p.m.</teams>\r<weather>Mostly sunny. Winds blowing out to center field at 5-10 m.p.h.  Game-time temperature: Around 80.</weather>\r</listing>\r</league>\r</forecast>\r<Detailed_Weather>\r<DW_Listing SportCode="AA" Sport="MLB">\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40439</GameID>\r<Gamedate>7/4/2014 11:05:00 AM</Gamedate>\r<AwayTeam>Chicago Cubs</AwayTeam>\r<HomeTeam>Washington Nationals</HomeTeam>\r<WeatherType>3</WeatherType>\r<Description>Mostly cloudy. Winds blowing in from left field at 10-15 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40442</GameID>\r<Gamedate>7/4/2014 5:05:00 PM</Gamedate>\r<AwayTeam>Philadelphia Phillies</AwayTeam>\r<HomeTeam>Pittsburgh Pirates</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing out to right field at 10-15 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40445</GameID>\r<Gamedate>7/4/2014 6:40:00 PM</Gamedate>\r<AwayTeam>San Francisco Giants</AwayTeam>\r<HomeTeam>San Diego Padres</HomeTeam>\r<WeatherType>2</WeatherType>\r<Description>Partly cloudy. Winds blowing out to right field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40443</GameID>\r<Gamedate>7/4/2014 7:10:00 PM</Gamedate>\r<AwayTeam>Milwaukee Brewers</AwayTeam>\r<HomeTeam>Cincinnati Reds</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing out to right field at 5-10 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40444</GameID>\r<Gamedate>7/4/2014 7:15:00 PM</Gamedate>\r<AwayTeam>Miami Marlins</AwayTeam>\r<HomeTeam>St. Louis Cardinals</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing in from right field at 5-10 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>80</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40441</GameID>\r<Gamedate>7/4/2014 7:35:00 PM</Gamedate>\r<AwayTeam>Arizona Diamondbacks</AwayTeam>\r<HomeTeam>Atlanta Braves</HomeTeam>\r<WeatherType>1</WeatherType>\r<Description>Mostly sunny. Winds blowing in from left field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>80</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40446</GameID>\r<Gamedate>7/4/2014 8:10:00 PM</Gamedate>\r<AwayTeam>Los Angeles Dodgers</AwayTeam>\r<HomeTeam>Colorado Rockies</HomeTeam>\r<WeatherType>2</WeatherType>\r<Description>Partly cloudy with a 30-percent chance of rain. Winds blowing out to right field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>80</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40440</GameID>\r<Gamedate>7/4/2014 7:10:00 PM</Gamedate>\r<AwayTeam>Texas Rangers</AwayTeam>\r<HomeTeam>New York Mets</HomeTeam>\r<WeatherType>2</WeatherType>\r<Description>Partly cloudy. Winds blowing in from left field at 10-20 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40432</GameID>\r<Gamedate>7/4/2014 1:35:00 PM</Gamedate>\r<AwayTeam>Baltimore Orioles</AwayTeam>\r<HomeTeam>Boston Red Sox</HomeTeam>\r<WeatherType>3</WeatherType>\r<Description>Cloudy with a 90-percent chance of rain. Winds blowing in from left field at 10-15 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40436</GameID>\r<Gamedate>7/4/2014 3:10:00 PM</Gamedate>\r<AwayTeam>New York Yankees</AwayTeam>\r<HomeTeam>Minnesota Twins</HomeTeam>\r<WeatherType>2</WeatherType>\r<Description>Partly cloudy. Winds blowing in from right field at 10-15 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40437</GameID>\r<Gamedate>7/4/2014 4:05:00 PM</Gamedate>\r<AwayTeam>Toronto Blue Jays</AwayTeam>\r<HomeTeam>Oakland Athletics</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing out to center field at 10-15 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>65</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40434</GameID>\r<Gamedate>7/4/2014 7:08:00 PM</Gamedate>\r<AwayTeam>Tampa Bay Rays</AwayTeam>\r<HomeTeam>Detroit Tigers</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing out to right field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>75</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40433</GameID>\r<Gamedate>7/4/2014 7:05:00 PM</Gamedate>\r<AwayTeam>Kansas City Royals</AwayTeam>\r<HomeTeam>Cleveland Indians</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing in from left field at 5-10 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>70</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40435</GameID>\r<Gamedate>7/4/2014 7:10:00 PM</Gamedate>\r<AwayTeam>Seattle Mariners</AwayTeam>\r<HomeTeam>Chicago White Sox</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds blowing in from center field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>60</Temperature>\r</Item>\r<Item>\r<Sportcode>AA</Sportcode>\r<GameID>40438</GameID>\r<Gamedate>7/4/2014 9:05:00 PM</Gamedate>\r<AwayTeam>Houston Astros</AwayTeam>\r<HomeTeam>LA Angels of Anaheim</HomeTeam>\r<WeatherType>1</WeatherType>\r<Description>Mostly sunny. Winds blowing out to center field at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>80</Temperature>\r</Item>\r</DW_Listing>\r<DW_Listing SportCode="AB" Sport="NFL">\r</DW_Listing>\r<DW_Listing SportCode="AJ" Sport="CFL">\r<Item>\r<Sportcode>AJ</Sportcode>\r<GameID>1223</GameID>\r<Gamedate>7/4/2014 7:00:00 PM</Gamedate>\r<AwayTeam>British Columbia Lions</AwayTeam>\r<HomeTeam>Montreal Alouettes</HomeTeam>\r<WeatherType>2</WeatherType>\r<Description>Partly cloudy. Winds northwest at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>65</Temperature>\r</Item>\r<Item>\r<Sportcode>AJ</Sportcode>\r<GameID>1224</GameID>\r<Gamedate>7/4/2014 10:00:00 PM</Gamedate>\r<AwayTeam>Hamilton Tiger-Cats</AwayTeam>\r<HomeTeam>Edmonton Eskimos</HomeTeam>\r<WeatherType>1</WeatherType>\r<Description>Mostly sunny. Winds northwest at 5-10 m.p.h.</Description>\r<TempAdjust>Around</TempAdjust>\r<Temperature>70</Temperature>\r</Item>\r<Item>\r<Sportcode>AJ</Sportcode>\r<GameID>1225</GameID>\r<Gamedate>7/5/2014 3:00:00 PM</Gamedate>\r<AwayTeam>Saskatchewan Roughriders</AwayTeam>\r<HomeTeam>Toronto Argonauts</HomeTeam>\r<WeatherType>0</WeatherType>\r<Description>Sunny. Winds west at 5-10 m.p.h.</Description>\r<TempAdjust>Near</TempAdjust>\r<Temperature>80</Temperature>\r</Item>\r</DW_Listing>\r<DW_Listing SportCode="AF" Sport="CFOOT">\r</DW_Listing>\r</Detailed_Weather>\r<time_stamp> July 4, 2014, at 08:53 AM ET </time_stamp>\r</message>\r
\ No newline at end of file