[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 <?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>
+ /// <Prop [rest of string was truncated]";.
+ /// </summary>
+ internal static string SelectAggregatesSample {
+ get {
+ return ResourceManager.GetString("SelectAggregatesSample", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?>
+ ///<BatchPropertyCollection>
+ /// <PropertyCollection>
+ /// <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>
+ /// </PropertyCollection>
+ /// <PropertyCollection>
+ /// <Property>
+ /// <Name>ID</Name>
+ /// <Type>int32</Type>
+ /// <Value>2</ [rest of string was truncated]";.
+ /// </summary>
+ internal static string SelectFeatureSample {
+ get {
+ return ResourceManager.GetString("SelectFeatureSample", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to <?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</Valu [rest of string was truncated]";.
+ /// </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