[mapguide-commits] r4892 - in sandbox/maestro-2.5: MaestroAPITests MaestroAPITests/Properties MaestroAPITests/Resources OSGeo.MapGuide.MaestroAPI.Http

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon May 17 04:46:56 EDT 2010


Author: jng
Date: 2010-05-17 04:46:48 -0400 (Mon, 17 May 2010)
New Revision: 4892

Added:
   sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.Designer.cs
   sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.resx
   sandbox/maestro-2.5/MaestroAPITests/Resources/
   sandbox/maestro-2.5/MaestroAPITests/Resources/SelectAggregatesSample.xml
   sandbox/maestro-2.5/MaestroAPITests/Resources/SelectFeatureSample.xml
   sandbox/maestro-2.5/MaestroAPITests/Resources/SelectSqlSample.xml
   sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlAggregateSetReader.cs
   sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlSqlResultReader.cs
Modified:
   sandbox/maestro-2.5/MaestroAPITests/FeatureReaderTests.cs
   sandbox/maestro-2.5/MaestroAPITests/MaestroAPITests.csproj
   sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
   sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj
   sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlFeatureSetReader.cs
Log:
Split the http FeatureSetReader impl into 3 separate implementations. Add unit tests to test each reader against the sample post-#708 xml output.

Modified: sandbox/maestro-2.5/MaestroAPITests/FeatureReaderTests.cs
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/FeatureReaderTests.cs	2010-05-17 07:10:17 UTC (rev 4891)
+++ sandbox/maestro-2.5/MaestroAPITests/FeatureReaderTests.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -21,6 +21,10 @@
 using System.Collections.Generic;
 using System.Text;
 using NUnit.Framework;
+using System.Xml;
+using System.IO;
+using OSGeo.MapGuide.MaestroAPI;
+using OSGeo.MapGuide.MaestroAPI.Http;
 
 namespace MaestroAPITests
 {
@@ -31,18 +35,78 @@
         public void TestXmlFeatureNullValues()
         {
             //Simulate post-#708 SELECTFEATURES and verify reader properly handles null values in response
+            var bytes = Encoding.UTF8.GetBytes(Properties.Resources.SelectFeatureSample);
+            var reader = new XmlFeatureSetReader(new MemoryStream(bytes));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsFalse(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsTrue(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
         }
 
         [Test]
         public void TestXmlAggregateNullValues()
         {
             //Simulate post-#708 SELECTAGGREGATES and verify reader properly handles null values in response
+            var bytes = Encoding.UTF8.GetBytes(Properties.Resources.SelectAggregatesSample);
+            var reader = new XmlAggregateSetReader(new MemoryStream(bytes));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsFalse(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsTrue(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
         }
         
         [Test]
         public void TestXmlSqlNullValues()
         {
             //Simulate post-#708 EXECUTESQL and verify reader properly handles null values in response
+            var bytes = Encoding.UTF8.GetBytes(Properties.Resources.SelectSqlSample);
+            var reader = new XmlSqlResultReader(new MemoryStream(bytes));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsFalse(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsFalse(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
+
+            reader.Read();
+
+            Assert.IsFalse(reader.IsDBNull(0));
+            Assert.IsTrue(reader.IsDBNull(1));
+            Assert.IsTrue(reader.IsDBNull(2));
         }
     }
 }

Modified: sandbox/maestro-2.5/MaestroAPITests/MaestroAPITests.csproj
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/MaestroAPITests.csproj	2010-05-17 07:10:17 UTC (rev 4891)
+++ sandbox/maestro-2.5/MaestroAPITests/MaestroAPITests.csproj	2010-05-17 08:46:48 UTC (rev 4892)
@@ -3,7 +3,7 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>9.0.21022</ProductVersion>
+    <ProductVersion>9.0.30729</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{351D49A3-2E4A-4EC3-AFC2-D56598F44F51}</ProjectGuid>
     <OutputType>Library</OutputType>
@@ -48,6 +48,11 @@
     <Compile Include="FeatureReaderTests.cs" />
     <Compile Include="HttpConnectionTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
     <Compile Include="ResourceTests.cs" />
     <Compile Include="RuntimeMapTests.cs" />
     <Compile Include="SerializationTests.cs" />
@@ -62,6 +67,21 @@
       <Name>OSGeo.MapGuide.MaestroAPI</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\SelectAggregatesSample.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\SelectFeatureSample.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\SelectSqlSample.xml" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

Added: sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.Designer.cs
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.Designer.cs	                        (rev 0)
+++ sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.Designer.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,150 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.4927
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MaestroAPITests.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MaestroAPITests.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+        ///&lt;PropertySet&gt;
+        ///    &lt;PropertyDefinitions&gt;
+        ///        &lt;PropertyDefinition&gt;
+        ///            &lt;Name&gt;ID&lt;/Name&gt;
+        ///            &lt;Type&gt;int32&lt;/Type&gt;
+        ///        &lt;/PropertyDefinition&gt;
+        ///        &lt;PropertyDefinition&gt;
+        ///            &lt;Name&gt;Name&lt;/Name&gt;
+        ///            &lt;Type&gt;string&lt;/Type&gt;
+        ///        &lt;/PropertyDefinition&gt;
+        ///        &lt;PropertyDefinition&gt;
+        ///            &lt;Name&gt;URL&lt;/Name&gt;
+        ///            &lt;Type&gt;string&lt;/Type&gt;
+        ///        &lt;/PropertyDefinition&gt;
+        ///    &lt;/PropertyDefinitions&gt;
+        ///    &lt;Properties&gt;
+        ///        &lt;Prop [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string SelectAggregatesSample {
+            get {
+                return ResourceManager.GetString("SelectAggregatesSample", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+        ///&lt;BatchPropertyCollection&gt;
+        ///	&lt;PropertyCollection&gt;
+        ///		&lt;Property&gt;
+        ///			&lt;Name&gt;ID&lt;/Name&gt;
+        ///			&lt;Type&gt;int32&lt;/Type&gt;
+        ///			&lt;Value&gt;1&lt;/Value&gt;
+        ///		&lt;/Property&gt;
+        ///		&lt;Property&gt;
+        ///			&lt;Name&gt;Name&lt;/Name&gt;
+        ///			&lt;Type&gt;string&lt;/Type&gt;
+        ///			&lt;Value&gt;Foobar&lt;/Value&gt;
+        ///		&lt;/Property&gt;
+        ///		&lt;Property&gt;
+        ///			&lt;Name&gt;URL&lt;/Name&gt;
+        ///			&lt;Type&gt;string&lt;/Type&gt;
+        ///			&lt;Value&gt;http://foobar.com&lt;/Value&gt;
+        ///		&lt;/Property&gt;
+        ///	&lt;/PropertyCollection&gt;
+        ///	&lt;PropertyCollection&gt;
+        ///		&lt;Property&gt;
+        ///			&lt;Name&gt;ID&lt;/Name&gt;
+        ///			&lt;Type&gt;int32&lt;/Type&gt;
+        ///			&lt;Value&gt;2&lt;/ [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string SelectFeatureSample {
+            get {
+                return ResourceManager.GetString("SelectFeatureSample", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+        ///&lt;RowSet&gt;
+        ///    &lt;ColumnDefinitions&gt;
+        ///        &lt;Column&gt;
+        ///            &lt;Name&gt;ID&lt;/Name&gt;
+        ///            &lt;Type&gt;int32&lt;/Type&gt;
+        ///        &lt;/Column&gt;
+        ///        &lt;Column&gt;
+        ///            &lt;Name&gt;Name&lt;/Name&gt;
+        ///            &lt;Type&gt;string&lt;/Type&gt;
+        ///        &lt;/Column&gt;
+        ///        &lt;Column&gt;
+        ///            &lt;Name&gt;URL&lt;/Name&gt;
+        ///            &lt;Type&gt;string&lt;/Type&gt;
+        ///        &lt;/Column&gt;
+        ///    &lt;/ColumnDefinitions&gt;
+        ///    &lt;Rows&gt;
+        ///        &lt;Row&gt;
+        ///            &lt;Column&gt;
+        ///                &lt;Name&gt;ID&lt;/Name&gt;
+        ///                &lt;Value&gt;1&lt;/Valu [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string SelectSqlSample {
+            get {
+                return ResourceManager.GetString("SelectSqlSample", resourceCulture);
+            }
+        }
+    }
+}

Added: sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.resx
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.resx	                        (rev 0)
+++ sandbox/maestro-2.5/MaestroAPITests/Properties/Resources.resx	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="SelectAggregatesSample" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\SelectAggregatesSample.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+  <data name="SelectFeatureSample" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\SelectFeatureSample.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+  <data name="SelectSqlSample" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\SelectSqlSample.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+</root>
\ No newline at end of file

Added: sandbox/maestro-2.5/MaestroAPITests/Resources/SelectAggregatesSample.xml
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/Resources/SelectAggregatesSample.xml	                        (rev 0)
+++ sandbox/maestro-2.5/MaestroAPITests/Resources/SelectAggregatesSample.xml	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PropertySet>
+    <PropertyDefinitions>
+        <PropertyDefinition>
+            <Name>ID</Name>
+            <Type>int32</Type>
+        </PropertyDefinition>
+        <PropertyDefinition>
+            <Name>Name</Name>
+            <Type>string</Type>
+        </PropertyDefinition>
+        <PropertyDefinition>
+            <Name>URL</Name>
+            <Type>string</Type>
+        </PropertyDefinition>
+    </PropertyDefinitions>
+    <Properties>
+        <PropertyCollection>
+            <Property>
+                <Name>ID</Name>
+                <Value>1</Value>
+            </Property>
+            <Property>
+                <Name>Name</Name>
+                <Value>Foobar</Value>
+            </Property>
+            <Property>
+                <Name>URL</Name>
+                <Value>http://foobar.com</Value>
+            </Property>
+        </PropertyCollection>
+        <PropertyCollection>
+            <Property>
+                <Name>ID</Name>
+                <Value>2</Value>
+            </Property>
+            <Property>
+                <Name>Name</Name>
+                <Value>Snafu</Value>
+            </Property>
+            <Property>
+                <Name>URL</Name>
+                <Value></Value>
+            </Property>
+        </PropertyCollection>
+        <PropertyCollection>
+            <Property>
+                <Name>ID</Name>
+                <Value>2</Value>
+            </Property>
+            <Property>
+                <Name>Name</Name>
+                <Value></Value>
+            </Property>
+            <Property>
+                <Name>URL</Name>
+                <Value></Value>
+            </Property>
+        </PropertyCollection>
+    </Properties>
+</PropertySet>
\ No newline at end of file

Added: sandbox/maestro-2.5/MaestroAPITests/Resources/SelectFeatureSample.xml
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/Resources/SelectFeatureSample.xml	                        (rev 0)
+++ sandbox/maestro-2.5/MaestroAPITests/Resources/SelectFeatureSample.xml	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FeatureSet>
+    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://fdo.osgeo.org/schemas/feature/Schema1" xmlns:fdo="http://fdo.osgeo.org/schemas" xmlns:gml="http://www.opengis.net/gml" xmlns:Schema1="http://fdo.osgeo.org/schemas/feature/Schema1" elementFormDefault="qualified" attributeFormDefault="unqualified">
+        <xs:annotation>
+            <xs:documentation/>
+            <xs:appinfo source="http://fdo.osgeo.org/schemas"/>
+        </xs:annotation>
+        <xs:element name="Foobar" type="Schema1:FoobarType" abstract="false" substitutionGroup="gml:_Feature">
+            <xs:key name="FoobarKey">
+                <xs:selector xpath=".//Foobar"/>
+                <xs:field xpath="ID"/>
+            </xs:key>
+        </xs:element>
+        <xs:complexType name="FoobarType" abstract="false">
+            <xs:annotation>
+                <xs:documentation/>
+                <xs:appinfo source="http://fdo.osgeo.org/schemas"/>
+            </xs:annotation>
+            <xs:complexContent>
+                <xs:extension base="fdo:ClassType">
+                    <xs:sequence>
+                        <xs:element name="ID" fdo:readOnly="true" minOccurs="0" fdo:autogenerated="true">
+                            <xs:simpleType>
+                                <xs:restriction base="fdo:int32"/>
+                            </xs:simpleType>
+                            <xs:annotation>
+                                <xs:documentation/>
+                                <xs:appinfo source="http://fdo.osgeo.org/schemas"/>
+                            </xs:annotation>
+                        </xs:element>
+                        <xs:element name="Name" minOccurs="0">
+                            <xs:annotation>
+                                <xs:documentation/>
+                                <xs:appinfo source="http://fdo.osgeo.org/schemas"/>
+                            </xs:annotation>
+                            <xs:simpleType>
+                                <xs:restriction base="xs:string">
+                                    <xs:maxLength value="255"/>
+                                </xs:restriction>
+                            </xs:simpleType>
+                        </xs:element>
+                        <xs:element name="URL" minOccurs="0">
+                            <xs:annotation>
+                                <xs:documentation/>
+                                <xs:appinfo source="http://fdo.osgeo.org/schemas"/>
+                            </xs:annotation>
+                            <xs:simpleType>
+                                <xs:restriction base="xs:string">
+                                    <xs:maxLength value="255"/>
+                                </xs:restriction>
+                            </xs:simpleType>
+                        </xs:element>
+                    </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:schema>
+    <Features>
+	    <Feature>
+		    <Property>
+			    <Name>ID</Name>
+			    <Type>int32</Type>
+			    <Value>1</Value>
+		    </Property>
+		    <Property>
+			    <Name>Name</Name>
+			    <Type>string</Type>
+			    <Value>Foobar</Value>
+		    </Property>
+		    <Property>
+			    <Name>URL</Name>
+			    <Type>string</Type>
+			    <Value>http://foobar.com</Value>
+		    </Property>
+	    </Feature>
+        <Feature>
+		    <Property>
+			    <Name>ID</Name>
+			    <Type>int32</Type>
+			    <Value>2</Value>
+		    </Property>
+		    <Property>
+			    <Name>Name</Name>
+			    <Type>string</Type>
+			    <Value>Snafu</Value>
+		    </Property>
+		    <Property>
+			    <Name>URL</Name>
+			    <Type>string</Type>
+		    </Property>
+	    </Feature>
+        <Feature>
+		    <Property>
+			    <Name>ID</Name>
+			    <Type>int32</Type>
+			    <Value>2</Value>
+		    </Property>
+		    <Property>
+			    <Name>Name</Name>
+			    <Type>string</Type>
+		    </Property>
+		    <Property>
+			    <Name>URL</Name>
+			    <Type>string</Type>
+		    </Property>
+	    </Feature>
+    </Features>
+</FeatureSet>
\ No newline at end of file

Added: sandbox/maestro-2.5/MaestroAPITests/Resources/SelectSqlSample.xml
===================================================================
--- sandbox/maestro-2.5/MaestroAPITests/Resources/SelectSqlSample.xml	                        (rev 0)
+++ sandbox/maestro-2.5/MaestroAPITests/Resources/SelectSqlSample.xml	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RowSet>
+    <ColumnDefinitions>
+        <Column>
+            <Name>ID</Name>
+            <Type>int32</Type>
+        </Column>
+        <Column>
+            <Name>Name</Name>
+            <Type>string</Type>
+        </Column>
+        <Column>
+            <Name>URL</Name>
+            <Type>string</Type>
+        </Column>
+    </ColumnDefinitions>
+    <Rows>
+        <Row>
+            <Column>
+                <Name>ID</Name>
+                <Value>1</Value>
+            </Column>
+            <Column>
+                <Name>Name</Name>
+                <Value>Foobar</Value>
+            </Column>
+            <Column>
+                <Name>URL</Name>
+                <Value>http://foobar.com</Value>
+            </Column>
+        </Row>
+        <Row>
+            <Column>
+                <Name>ID</Name>
+                <Value>2</Value>
+            </Column>
+            <Column>
+                <Name>Name</Name>
+                <Value>Snafu</Value>
+            </Column>
+            <Column>
+                <Name>URL</Name>
+                <Value></Value>
+            </Column>
+        </Row>
+        <Row>
+            <Column>
+                <Name>ID</Name>
+                <Value>2</Value>
+            </Column>
+            <Column>
+                <Name>Name</Name>
+                <Value></Value>
+            </Column>
+            <Column>
+                <Name>URL</Name>
+                <Value></Value>
+            </Column>
+        </Row>
+    </Rows>	
+</RowSet>
\ No newline at end of file

Modified: sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
===================================================================
--- sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2010-05-17 07:10:17 UTC (rev 4891)
+++ sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -519,7 +519,7 @@
             ResourceIdentifier.Validate(featureSourceID, ResourceTypes.FeatureSource);
             string req = m_reqBuilder.ExecuteSqlQuery(featureSourceID, sql);
 
-            return new XmlFeatureSetReader(this.OpenRead(req));
+            return new XmlSqlResultReader(this.OpenRead(req));
         }
 
 		public FeatureSetReader QueryFeatureSource(string resourceID, string schema, string query)
@@ -561,7 +561,10 @@
                     rs.Flush();
                 }
 
-                return new XmlFeatureSetReader(req.GetResponse().GetResponseStream());
+                if (aggregate)
+                    return new XmlAggregateSetReader(req.GetResponse().GetResponseStream());
+                else
+                    return new XmlFeatureSetReader(req.GetResponse().GetResponseStream());
             }
             catch (Exception ex)
             {

Modified: sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj
===================================================================
--- sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj	2010-05-17 07:10:17 UTC (rev 4891)
+++ sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj	2010-05-17 08:46:48 UTC (rev 4892)
@@ -45,7 +45,9 @@
     <Compile Include="HttpServerConnection.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RequestBuilder.cs" />
+    <Compile Include="XmlAggregateSetReader.cs" />
     <Compile Include="XmlFeatureSetReader.cs" />
+    <Compile Include="XmlSqlResultReader.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\OSGeo.MapGuide.MaestroAPI\OSGeo.MapGuide.MaestroAPI.csproj">

Added: sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlAggregateSetReader.cs
===================================================================
--- sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlAggregateSetReader.cs	                        (rev 0)
+++ sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlAggregateSetReader.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,281 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+using System.IO;
+
+namespace OSGeo.MapGuide.MaestroAPI.Http
+{
+    public class XmlAggregateSetReader : FeatureSetReader
+    {
+        private XmlTextReader m_reader;
+
+		//TODO: Make internal
+        public XmlAggregateSetReader(Stream m_source)
+            : base()
+		{
+			m_reader = new XmlTextReader(m_source);
+			m_reader.WhitespaceHandling = WhitespaceHandling.Significant;
+
+			//First we extract the response layout
+			m_reader.Read();
+			if (m_reader.Name != "xml")
+				throw new Exception("Bad document");
+			m_reader.Read();
+			if (m_reader.Name != "PropertySet")
+				throw new Exception("Bad document");
+
+            m_reader.Read();
+            if (m_reader.Name != "PropertyDefinitions")
+                throw new Exception("Bad document");
+
+			XmlDocument doc = new XmlDocument();
+			doc.LoadXml(m_reader.ReadOuterXml());
+			XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
+			mgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");
+			mgr.AddNamespace("gml", "http://www.opengis.net/gml");
+			mgr.AddNamespace("fdo", "http://fdo.osgeo.org/schemas");
+
+			//TODO: Assumes there is only one type returned... perhaps more can be returned....
+			XmlNodeList lst = doc.SelectNodes("PropertyDefinitions/PropertyDefinition");
+			FeatureSetColumn[] cols = new FeatureSetColumn[lst.Count];
+			for(int i = 0;i<lst.Count;i++)
+                cols[i] = new XmlAggregateSetColumn(lst[i]);
+
+            InitColumns(cols);
+
+			m_row = null;
+
+			if (m_reader.Name != "Properties")
+				throw new Exception("Bad document");
+
+			m_reader.Read();
+
+            if (m_reader.NodeType != XmlNodeType.EndElement)
+            {
+                if (m_reader.Name == "PropertyCollection")
+                {
+                    //OK
+                }
+                else
+                    throw new Exception("Bad document");
+            }
+		}
+
+        protected override bool ReadInternal()
+        {
+            if (m_reader == null || (m_reader.Name != "PropertyCollection"))
+            {
+                m_row = null;
+                return false;
+            }
+            return true;
+        }
+
+        protected override FeatureSetRow ProcessFeatureRow()
+        {
+            string xmlfragment = m_reader.ReadOuterXml();
+            XmlDocument doc = new XmlDocument();
+            doc.LoadXml(xmlfragment);
+
+            FeatureSetRow row = null;
+
+            if (doc["PropertyCollection"] != null)
+                row = new XmlAggregateSetRow(this, doc["PropertyCollection"]);
+
+            if (m_reader.Name != "PropertyCollection")
+            {
+                m_reader.Close();
+                m_reader = null;
+            }
+
+            return row;
+        }
+
+        protected override void CloseInternal()
+        {
+            
+        }
+
+        public override int Depth
+        {
+            get { throw new NotImplementedException(); }
+        }
+
+        public override System.Data.DataTable GetSchemaTable()
+        {
+            throw new NotImplementedException();
+        }
+
+        public override int RecordsAffected
+        {
+            get { throw new NotImplementedException(); }
+        }
+    }
+
+    public class XmlAggregateSetRow : FeatureSetRow
+    {
+        internal XmlAggregateSetRow(FeatureSetReader parent, XmlNode node)
+			: base(parent)
+		{
+            string nodeName = "Property";
+
+            foreach (XmlNode p in node.SelectNodes(nodeName))
+            {
+                int ordinal = GetOrdinal(p["Name"].InnerText);
+                if (!m_nulls[ordinal])
+                    throw new Exception("Bad document, multiple: " + p["Name"].InnerText + " values in a single feature");
+                m_nulls[ordinal] = false;
+
+                XmlNode valueNode = p["Value"];
+                if (valueNode == null || string.IsNullOrEmpty(valueNode.InnerText))
+                {
+                    m_nulls[ordinal] = true;
+                }
+                else
+                {
+                    if (parent.Columns[ordinal].Type == typeof(string) || parent.Columns[ordinal].Type == Utility.UnmappedType)
+                        m_items[ordinal] = valueNode.InnerText;
+                    else if (parent.Columns[ordinal].Type == typeof(int))
+                        m_items[ordinal] = XmlConvert.ToInt32(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(long))
+                        m_items[ordinal] = XmlConvert.ToInt64(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(short))
+                        m_items[ordinal] = XmlConvert.ToInt16(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(double))
+                        m_items[ordinal] = XmlConvert.ToDouble(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(bool))
+                        m_items[ordinal] = XmlConvert.ToBoolean(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(DateTime))
+                    {
+                        try
+                        {
+                            //Fix for broken ODBC provider
+                            string v = valueNode.InnerText;
+
+                            if (v.Trim().ToUpper().StartsWith("TIMESTAMP"))
+                                v = v.Trim().Substring("TIMESTAMP".Length).Trim();
+                            else if (v.Trim().ToUpper().StartsWith("DATE"))
+                                v = v.Trim().Substring("DATE".Length).Trim();
+                            else if (v.Trim().ToUpper().StartsWith("TIME"))
+                                v = v.Trim().Substring("TIME".Length).Trim();
+
+                            if (v != valueNode.InnerText)
+                            {
+                                if (v.StartsWith("'"))
+                                    v = v.Substring(1);
+                                if (v.EndsWith("'"))
+                                    v = v.Substring(0, v.Length - 1);
+
+                                m_items[ordinal] = DateTime.Parse(v, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.NoCurrentDateDefault);
+                            }
+                            else
+                                m_items[ordinal] = XmlConvert.ToDateTime(v, XmlDateTimeSerializationMode.Unspecified);
+                        }
+                        catch (Exception ex)
+                        {
+                            //Unfortunately FDO supports invalid dates, such as the 30th feb
+                            m_nulls[ordinal] = true;
+                            m_items[ordinal] = ex;
+                        }
+                    }
+                    else if (parent.Columns[ordinal].Type == Utility.GeometryType)
+                    {
+                        m_items[ordinal] = valueNode.InnerText;
+                        if (string.IsNullOrEmpty(valueNode.InnerText))
+                        {
+                            m_nulls[ordinal] = true;
+                            m_items[ordinal] = null;
+                        }
+                        else
+                            m_lazyloadGeometry[ordinal] = true;
+                    }
+                    else
+                        throw new Exception("Unknown type: " + parent.Columns[ordinal].Type.FullName);
+                }
+            }
+		}
+    }
+
+    public class XmlAggregateSetColumn : FeatureSetColumn
+    {
+        internal XmlAggregateSetColumn(XmlNode node) : base()
+		{
+            if (node.Name == "PropertyDefinition")
+            {
+                m_name = node["Name"].InnerText;
+                m_allowNull = true;
+                switch (node["Type"].InnerText.ToLower().Trim())
+                {
+                    case "string":
+                        m_type = typeof(string);
+                        break;
+                    case "byte":
+                        m_type = typeof(Byte);
+                        break;
+                    case "int32":
+                    case "int":
+                    case "integer":
+                        m_type = typeof(int);
+                        break;
+                    case "int16":
+                        m_type = typeof(short);
+                        break;
+                    case "int64":
+                    case "long":
+                        m_type = typeof(long);
+                        break;
+                    case "float":
+                    case "single":
+                        m_type = typeof(float);
+                        break;
+                    case "double":
+                    case "decimal":
+                        m_type = typeof(double);
+                        break;
+                    case "boolean":
+                    case "bool":
+                        m_type = typeof(bool);
+                        return;
+                    case "datetime":
+                    case "date":
+                        m_type = typeof(DateTime);
+                        break;
+                    case "raster":
+                        m_type = Utility.RasterType;
+                        break;
+                    case "geometry":
+                        m_type = Utility.GeometryType;
+                        break;
+                    default:
+                        //throw new Exception("Failed to find appropriate type for: " + node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value);
+                        m_type = Utility.UnmappedType;
+                        break;
+                }
+            }
+            else
+            {
+                throw new Exception("Bad document. Expected element: PropertyDefinition"); //LOCALIZE
+            }
+		}
+    }
+}

Modified: sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlFeatureSetReader.cs
===================================================================
--- sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlFeatureSetReader.cs	2010-05-17 07:10:17 UTC (rev 4891)
+++ sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlFeatureSetReader.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -40,11 +40,11 @@
 			if (m_reader.Name != "xml")
 				throw new Exception("Bad document");
 			m_reader.Read();
-			if (m_reader.Name != "FeatureSet" && m_reader.Name != "PropertySet" && m_reader.Name != "RowSet")
+			if (m_reader.Name != "FeatureSet")
 				throw new Exception("Bad document");
 
             m_reader.Read();
-            if (m_reader.Name != "xs:schema" && m_reader.Name != "PropertyDefinitions" && m_reader.Name != "ColumnDefinitions")
+            if (m_reader.Name != "xs:schema")
                 throw new Exception("Bad document");
 
 			XmlDocument doc = new XmlDocument();
@@ -55,13 +55,10 @@
 			mgr.AddNamespace("fdo", "http://fdo.osgeo.org/schemas");
 
 			//TODO: Assumes there is only one type returned... perhaps more can be returned....
-			XmlNodeList lst = doc.SelectNodes("xs:schema/xs:complexType/xs:complexContent/xs:extension/xs:sequence/xs:element", mgr);
-			if (lst.Count == 0)
-				lst = doc.SelectNodes("xs:schema/xs:complexType/xs:sequence/xs:element", mgr);
+            XmlNodeList lst = doc.SelectNodes("xs:schema/xs:complexType/xs:complexContent/xs:extension/xs:sequence/xs:element", mgr);
             if (lst.Count == 0)
-                lst = doc.SelectNodes("PropertyDefinitions/PropertyDefinition");
-            if (lst.Count == 0)
-                lst = doc.SelectNodes("ColumnDefinitions/Column");
+                lst = doc.SelectNodes("xs:schema/xs:complexType/xs:sequence/xs:element", mgr);
+
 			FeatureSetColumn[] cols = new FeatureSetColumn[lst.Count];
 			for(int i = 0;i<lst.Count;i++)
                 cols[i] = new XmlFeatureSetColumn(lst[i]);
@@ -70,7 +67,7 @@
 
 			m_row = null;
 
-			if (m_reader.Name != "Features" && m_reader.Name != "Properties" && m_reader.Name != "Rows")
+			if (m_reader.Name != "Features")
 				throw new Exception("Bad document");
 
 			m_reader.Read();
@@ -79,18 +76,15 @@
             {
                 if (m_reader.Name == "Features")
                     m_reader = null; //No features :(
-                else if (m_reader.Name == "PropertyCollection" || m_reader.Name == "Row")
-                {
-                    //OK
-                }
-                else if (m_reader.Name != "Feature")
+                
+                if (m_reader.Name != "Feature")
                     throw new Exception("Bad document");
             }
 		}
 
         protected override bool ReadInternal()
         {
-            if (m_reader == null || (m_reader.Name != "Feature" && m_reader.Name != "PropertyCollection" && m_reader.Name != "Row"))
+            if (m_reader == null || (m_reader.Name != "Feature"))
             {
                 m_row = null;
                 return false;
@@ -106,14 +100,10 @@
 
             FeatureSetRow row = null;
 
-            if (doc["Row"] != null)
-                row = new XmlFeatureSetRow(this, doc["Row"]);
-            else if (doc["Feature"] == null)
-                row = new XmlFeatureSetRow(this, doc["PropertyCollection"]);
-            else
+            if (doc["Feature"] != null)
                 row = new XmlFeatureSetRow(this, doc["Feature"]);
 
-            if (m_reader.Name != "Feature" && m_reader.Name != "PropertyCollection" && m_reader.Name != "Row")
+            if (m_reader.Name != "Feature")
             {
                 m_reader.Close();
                 m_reader = null;
@@ -149,8 +139,6 @@
 			: base(parent)
 		{
             string nodeName = "Property";
-            if (node.Name == "Row")
-                nodeName = "Column";
 
             foreach (XmlNode p in node.SelectNodes(nodeName))
             {
@@ -233,105 +221,50 @@
     {
         internal XmlFeatureSetColumn(XmlNode node) : base()
 		{
-            if (node.Name == "PropertyDefinition" || node.Name == "Column")
-            {
-                m_name = node["Name"].InnerText;
-                m_allowNull = true;
-                switch (node["Type"].InnerText.ToLower().Trim())
+            m_name = node.Attributes["name"].Value;
+            m_allowNull = node.Attributes["minOccurs"] != null && node.Attributes["minOccurs"].Value == "0";
+            if (node.Attributes["type"] != null && node.Attributes["type"].Value == "gml:AbstractGeometryType")
+                m_type = Utility.GeometryType;
+            else if (node["xs:simpleType"] == null)
+                m_type = Utility.RasterType;
+            else
+                switch (node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value.ToLower())
                 {
-                    case "string":
+                    case "xs:string":
                         m_type = typeof(string);
                         break;
-                    case "byte":
+                    case "fdo:byte":
                         m_type = typeof(Byte);
                         break;
-                    case "int32":
-                    case "int":
-                    case "integer":
+                    case "fdo:int32":
                         m_type = typeof(int);
                         break;
-                    case "int16":
+                    case "fdo:int16":
                         m_type = typeof(short);
                         break;
-                    case "int64":
-                    case "long":
+                    case "fdo:int64":
                         m_type = typeof(long);
                         break;
-                    case "float":
-                    case "single":
+                    case "xs:float":
+                    case "xs:single":
+                    case "fdo:single":
                         m_type = typeof(float);
                         break;
-                    case "double":
-                    case "decimal":
+                    case "xs:double":
+                    case "xs:decimal":
                         m_type = typeof(double);
                         break;
-                    case "boolean":
-                    case "bool":
+                    case "xs:boolean":
                         m_type = typeof(bool);
                         return;
-                    case "datetime":
-                    case "date":
+                    case "xs:datetime":
                         m_type = typeof(DateTime);
                         break;
-                    case "raster":
-                        m_type = Utility.RasterType;
-                        break;
-                    case "geometry":
-                        m_type = Utility.GeometryType;
-                        break;
                     default:
                         //throw new Exception("Failed to find appropriate type for: " + node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value);
                         m_type = Utility.UnmappedType;
                         break;
                 }
-            }
-            else
-            {
-                m_name = node.Attributes["name"].Value;
-                m_allowNull = node.Attributes["minOccurs"] != null && node.Attributes["minOccurs"].Value == "0";
-                if (node.Attributes["type"] != null && node.Attributes["type"].Value == "gml:AbstractGeometryType")
-                    m_type = Utility.GeometryType;
-                else if (node["xs:simpleType"] == null)
-                    m_type = Utility.RasterType;
-                else
-                    switch (node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value.ToLower())
-                    {
-                        case "xs:string":
-                            m_type = typeof(string);
-                            break;
-                        case "fdo:byte":
-                            m_type = typeof(Byte);
-                            break;
-                        case "fdo:int32":
-                            m_type = typeof(int);
-                            break;
-                        case "fdo:int16":
-                            m_type = typeof(short);
-                            break;
-                        case "fdo:int64":
-                            m_type = typeof(long);
-                            break;
-                        case "xs:float":
-                        case "xs:single":
-                        case "fdo:single":
-                            m_type = typeof(float);
-                            break;
-                        case "xs:double":
-                        case "xs:decimal":
-                            m_type = typeof(double);
-                            break;
-                        case "xs:boolean":
-                            m_type = typeof(bool);
-                            return;
-                        case "xs:datetime":
-                            m_type = typeof(DateTime);
-                            break;
-                        default:
-                            //throw new Exception("Failed to find appropriate type for: " + node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value);
-                            m_type = Utility.UnmappedType;
-                            break;
-                    }
-            }
 		}
     }
 }

Added: sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlSqlResultReader.cs
===================================================================
--- sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlSqlResultReader.cs	                        (rev 0)
+++ sandbox/maestro-2.5/OSGeo.MapGuide.MaestroAPI.Http/XmlSqlResultReader.cs	2010-05-17 08:46:48 UTC (rev 4892)
@@ -0,0 +1,281 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+using System.IO;
+
+namespace OSGeo.MapGuide.MaestroAPI.Http
+{
+    public class XmlSqlResultReader : FeatureSetReader
+    {
+        private XmlTextReader m_reader;
+
+		//TODO: Make internal
+        public XmlSqlResultReader(Stream m_source)
+            : base()
+		{
+			m_reader = new XmlTextReader(m_source);
+			m_reader.WhitespaceHandling = WhitespaceHandling.Significant;
+
+			//First we extract the response layout
+			m_reader.Read();
+			if (m_reader.Name != "xml")
+				throw new Exception("Bad document");
+			m_reader.Read();
+			if (m_reader.Name != "RowSet")
+				throw new Exception("Bad document");
+
+            m_reader.Read();
+            if (m_reader.Name != "ColumnDefinitions")
+                throw new Exception("Bad document");
+
+			XmlDocument doc = new XmlDocument();
+			doc.LoadXml(m_reader.ReadOuterXml());
+			XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
+			mgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");
+			mgr.AddNamespace("gml", "http://www.opengis.net/gml");
+			mgr.AddNamespace("fdo", "http://fdo.osgeo.org/schemas");
+
+			//TODO: Assumes there is only one type returned... perhaps more can be returned....
+            XmlNodeList lst = doc.SelectNodes("ColumnDefinitions/Column");
+			FeatureSetColumn[] cols = new FeatureSetColumn[lst.Count];
+			for(int i = 0;i<lst.Count;i++)
+                cols[i] = new XmlSqlResultColumn(lst[i]);
+
+            InitColumns(cols);
+
+			m_row = null;
+
+			if (m_reader.Name != "Rows")
+				throw new Exception("Bad document");
+
+			m_reader.Read();
+
+            if (m_reader.NodeType != XmlNodeType.EndElement)
+            {
+                if (m_reader.Name == "Row")
+                {
+                    //OK
+                }
+                else
+                    throw new Exception("Bad document");
+            }
+		}
+
+        protected override bool ReadInternal()
+        {
+            if (m_reader == null || (m_reader.Name != "Row"))
+            {
+                m_row = null;
+                return false;
+            }
+            return true;
+        }
+
+        protected override FeatureSetRow ProcessFeatureRow()
+        {
+            string xmlfragment = m_reader.ReadOuterXml();
+            XmlDocument doc = new XmlDocument();
+            doc.LoadXml(xmlfragment);
+
+            FeatureSetRow row = null;
+
+            if (doc["Row"] != null)
+                row = new XmlSqlResultRow(this, doc["Row"]);
+
+            if (m_reader.Name != "Row")
+            {
+                m_reader.Close();
+                m_reader = null;
+            }
+
+            return row;
+        }
+
+        protected override void CloseInternal()
+        {
+            
+        }
+
+        public override int Depth
+        {
+            get { throw new NotImplementedException(); }
+        }
+
+        public override System.Data.DataTable GetSchemaTable()
+        {
+            throw new NotImplementedException();
+        }
+
+        public override int RecordsAffected
+        {
+            get { throw new NotImplementedException(); }
+        }
+    }
+
+    public class XmlSqlResultRow : FeatureSetRow
+    {
+        internal XmlSqlResultRow(FeatureSetReader parent, XmlNode node)
+			: base(parent)
+		{
+            string nodeName = "Column";
+
+            foreach (XmlNode p in node.SelectNodes(nodeName))
+            {
+                int ordinal = GetOrdinal(p["Name"].InnerText);
+                if (!m_nulls[ordinal])
+                    throw new Exception("Bad document, multiple: " + p["Name"].InnerText + " values in a single feature");
+                m_nulls[ordinal] = false;
+
+                XmlNode valueNode = p["Value"];
+                if (valueNode == null || string.IsNullOrEmpty(valueNode.InnerText))
+                {
+                    m_nulls[ordinal] = true;
+                }
+                else
+                {
+                    if (parent.Columns[ordinal].Type == typeof(string) || parent.Columns[ordinal].Type == Utility.UnmappedType)
+                        m_items[ordinal] = valueNode.InnerText;
+                    else if (parent.Columns[ordinal].Type == typeof(int))
+                        m_items[ordinal] = XmlConvert.ToInt32(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(long))
+                        m_items[ordinal] = XmlConvert.ToInt64(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(short))
+                        m_items[ordinal] = XmlConvert.ToInt16(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(double))
+                        m_items[ordinal] = XmlConvert.ToDouble(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(bool))
+                        m_items[ordinal] = XmlConvert.ToBoolean(valueNode.InnerText);
+                    else if (parent.Columns[ordinal].Type == typeof(DateTime))
+                    {
+                        try
+                        {
+                            //Fix for broken ODBC provider
+                            string v = valueNode.InnerText;
+
+                            if (v.Trim().ToUpper().StartsWith("TIMESTAMP"))
+                                v = v.Trim().Substring("TIMESTAMP".Length).Trim();
+                            else if (v.Trim().ToUpper().StartsWith("DATE"))
+                                v = v.Trim().Substring("DATE".Length).Trim();
+                            else if (v.Trim().ToUpper().StartsWith("TIME"))
+                                v = v.Trim().Substring("TIME".Length).Trim();
+
+                            if (v != valueNode.InnerText)
+                            {
+                                if (v.StartsWith("'"))
+                                    v = v.Substring(1);
+                                if (v.EndsWith("'"))
+                                    v = v.Substring(0, v.Length - 1);
+
+                                m_items[ordinal] = DateTime.Parse(v, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.NoCurrentDateDefault);
+                            }
+                            else
+                                m_items[ordinal] = XmlConvert.ToDateTime(v, XmlDateTimeSerializationMode.Unspecified);
+                        }
+                        catch (Exception ex)
+                        {
+                            //Unfortunately FDO supports invalid dates, such as the 30th feb
+                            m_nulls[ordinal] = true;
+                            m_items[ordinal] = ex;
+                        }
+                    }
+                    else if (parent.Columns[ordinal].Type == Utility.GeometryType)
+                    {
+                        m_items[ordinal] = valueNode.InnerText;
+                        if (string.IsNullOrEmpty(valueNode.InnerText))
+                        {
+                            m_nulls[ordinal] = true;
+                            m_items[ordinal] = null;
+                        }
+                        else
+                            m_lazyloadGeometry[ordinal] = true;
+                    }
+                    else
+                        throw new Exception("Unknown type: " + parent.Columns[ordinal].Type.FullName);
+                }
+            }
+		}
+    }
+
+    public class XmlSqlResultColumn : FeatureSetColumn
+    {
+        internal XmlSqlResultColumn(XmlNode node) : base()
+		{
+            if (node.Name == "Column")
+            {
+                m_name = node["Name"].InnerText;
+                m_allowNull = true;
+                switch (node["Type"].InnerText.ToLower().Trim())
+                {
+                    case "string":
+                        m_type = typeof(string);
+                        break;
+                    case "byte":
+                        m_type = typeof(Byte);
+                        break;
+                    case "int32":
+                    case "int":
+                    case "integer":
+                        m_type = typeof(int);
+                        break;
+                    case "int16":
+                        m_type = typeof(short);
+                        break;
+                    case "int64":
+                    case "long":
+                        m_type = typeof(long);
+                        break;
+                    case "float":
+                    case "single":
+                        m_type = typeof(float);
+                        break;
+                    case "double":
+                    case "decimal":
+                        m_type = typeof(double);
+                        break;
+                    case "boolean":
+                    case "bool":
+                        m_type = typeof(bool);
+                        return;
+                    case "datetime":
+                    case "date":
+                        m_type = typeof(DateTime);
+                        break;
+                    case "raster":
+                        m_type = Utility.RasterType;
+                        break;
+                    case "geometry":
+                        m_type = Utility.GeometryType;
+                        break;
+                    default:
+                        //throw new Exception("Failed to find appropriate type for: " + node["xs:simpleType"]["xs:restriction"].Attributes["base"].Value);
+                        m_type = Utility.UnmappedType;
+                        break;
+                }
+            }
+            else
+            {
+                throw new Exception("Bad document. Expected element: PropertyDefinition"); //LOCALIZE
+            }
+		}
+    }
+}



More information about the mapguide-commits mailing list