ThinkGeo.com    |     Documentation    |     Premium Support

FromXMLString()/ToXMLString() in 3.0

We have many custom drawn shapes from our existing application built on MapSuite 2.0, and need a way to be able to read all those shapes at runtime in MapSuite 3.0. They are stored in a database as text, using FromXMLString/ToXMLString to convert them back and forth from BaseAreaShapes. The 2 systems will be sharing a data source for a while, so I need a way in 3.0 to read and write to XML. Can you provide me with the code for those 2 functions that take/return AreaBaseShapes?






 


Rob,


Map Suite can read/write XMLs but I'm afraid they are not compatible with the format of 2.0.  If your XMLs are simple though, I think it might not be that hard to write a quick method to parse it in 3.0 ourselves. So are all your XMLs for area shapes? Can you send your data to us for test as maybe we can make a simple one for you?


BTW: here is how 3.0 Read/Write XML files, please have a look if you are interested.


gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/12/aft/5445/afv/topic/Default.aspx


Thanks,


Ben


 



They are all simple shapes that users have drawn using track shapes. They are all area shapes. Here is a sample shape: 
  
 
<?xml version="1.0"?>
<Polygon xmlns:xsd="w3.org/2001/XMLSchema" xmlns:xsi="w3.org/2001/XMLSchema-instance">
<Key>2a9364fd-304a-4f8b-b323-579a3f017ba5
<Selected>false
<Parts>
<MultiPoint>
<Key>45fafe6e-3641-4f22-93ef-74deefdd64b5
<Selected>false
<RingType>OuterRing
<RingOrder>ClockWise
<Points>
<PointShape>
<Key>2f5c1179-aa51-4395-a2c5-3f3ebd9af185 
<Selected>false
<X>-117.95769810098796
<Y>33.630242577304507

<PointShape>
<Key>6b928364-1380-432c-b236-033850bbaa48
<Selected>false
<X>-117.94542348604963
<Y>33.672619224115373

<PointShape>
<Key>7fdf85aa-69fa-4cf2-9983-6b3e37165975
<Selected>false
<X>-117.91999749796312
<Y>33.672911476852

<PointShape>
<Key>54218142-242a-43bf-9624-dff1b98e8e0b
<Selected>false
<X>-117.91882848701661
<Y>33.644270708662582

<PointShape>
<Key>b39191af-5de5-49a0-92a2-4e25b072f485
<Selected>false
<X>-117.93519464026771
<Y>33.626443291728357

<PointShape>
<Key>204f4fa1-91ae-4c24-b547-5a109636a94d
<Selected>false
<X>-117.94279321142
<Y>33.620890489732453

<PointShape>
<Key>e3c563cc-cd53-4f80-8741-230a3821a6b4
<Selected>false
<X>-117.94279321142
<Y>33.620890489732453




</Polygon>


Rob, 
  
   Is it ok if the method we write always produces a multi polygon?  Are all of the xml snippets you have multi polygon type?  If this were true we can build the routines quickly and multi polygon can bu just one ring and can represent all kinds of area shapes. 
  
 David

That would be great. We have a variety of shape types stored in 2.0’s XML though (Polygon, Ellipse, StraightRectangle). If they were all converted to MultipolygonShapes at runtime, that would be easy to work with. 
  
 As for saving shapes back to 2.0 compatible XML, it might make sense to also always save to Polygon (using multiple parts). 
  
 Here is the code I put together to hold me over for reading 2.0 shapes into an AreaBaseShape. For polygons, it only handles single part polygons for now. 
 
AreaBaseShape areaBaseShape = null;
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xml); // xml is the input text
if (xdoc.ChildNodes[1].Name == “Polygon”)
{
  XmlNodeList points = xdoc.GetElementsByTagName(“PointShape”);
  if (points.Count > 0)
  {
    PolygonShape poly = new PolygonShape();
    for (int i = 0; i < points.Count; i++)
    {
      double x = Convert.ToDouble(points[i].LastChild.PreviousSibling.InnerText);
      double y = Convert.ToDouble(points[i].LastChild.InnerText);
      poly.OuterRing.Vertices.Add(new Vertex(x, y));
    }
    // add first point to end
    poly.OuterRing.Vertices.Add(poly.OuterRing.Vertices[0]);
    areaBaseShape = poly;
  }
}
else if (xdoc.ChildNodes[1].Name == “Ellipse”)
{
  double width = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].InnerText);
  double height = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].InnerText);
  double centerX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[4].LastChild.PreviousSibling.InnerText);
  double centerY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[4].LastChild.InnerText);
  areaBaseShape = new EllipseShape(new PointShape(centerX, centerY), width, height);
}
else if (xdoc.ChildNodes[1].Name == “StraightRectangle”)
{
  double minX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].ChildNodes[2].InnerText);
  double maxY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].ChildNodes[3].InnerText);
  double maxX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].ChildNodes[2].InnerText);
  double minY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].ChildNodes[3].InnerText);
  areaBaseShape = new RectangleShape(minX, maxY, maxX, minY);
}





 


Rob,



Try this out.  We found a bug we think in the 2.x with inner rings and the XML.  I will confirm this and let you know. Anyway try out the solution.




David




555-MapSuite2.0XmlSupport.zip (14.3 KB)

Looks good. I noticed that it still only supports a Polygon with 1 MultiPoint Part for reading XML. For writing XML, it only supports a MultipolygonShape with PolygonShapes that only have an outer ring. 
  
 We will have the 2 systems (2.0 / 3.0) running side by side off the same data source while we transition our clients over to the new interface. This gives them the ability to define some pretty complex shapes in 3.0, and go back into the older version, and expect them to be there. So it is important that we can convert all possible AreaShapes between the two versions. I wish we could just flip a switch and have everyone be on the new version :)

This is what I came up with. When reading the XML, I assume that the order of MultiPoints are OuterRing, [0 or more InnerRings], next OuterRing, [0 or more InnerRings], etc. Is that always going to be correct in 2.0’s ToXMLString()? 
  
 I believe the only issue with the code is the ClockWise vs CounterClockWise RingOrder. Do I need to add some ring order checking? 
 
// assumes the order of MultiPoints are OuterRing, [0 or more InnerRings], next OuterRing, [0 or more InnerRings], etc
public static MultipolygonShape GetMultiPolygonShape(string xml)
{
    XmlDocument xdoc = new XmlDocument();
    xdoc.LoadXml(xml);

    MultipolygonShape returnMultiPolygonShape = new MultipolygonShape();
    if (xdoc.ChildNodes[1].Name == “Polygon”)
    {
        XmlNodeList multipoints = xdoc.GetElementsByTagName(“MultiPoint”);
        if (multipoints.Count > 0)
        {
            for (int i = 0; i < multipoints.Count; i++)
            {
                XmlNodeList points = multipoints[i].LastChild.ChildNodes;
                string ringType = points[0].ParentNode.PreviousSibling.PreviousSibling.InnerText;
                if (points.Count > 0)
                {
                    PolygonShape poly;
                    if (ringType == “OuterRing”)
                    {
                        poly = new PolygonShape();
                        for (int j = 0; j < points.Count; j++)
                        {
                            double x = Convert.ToDouble(points[j].LastChild.PreviousSibling.InnerText);
                            double y = Convert.ToDouble(points[j].LastChild.InnerText);
                            poly.OuterRing.Vertices.Add(new Vertex(x, y));
                        }
                        poly.OuterRing.Vertices.Add(poly.OuterRing.Vertices[0]);
                        returnMultiPolygonShape.Polygons.Add(poly);
                    }
                    else
                    {
                        poly = returnMultiPolygonShape.Polygons[returnMultiPolygonShape.Polygons.Count - 1];
                        poly.InnerRings.Add(new RingShape());
                        int innerRingIndex = poly.InnerRings.Count - 1;
                        for (int j = 0; j < points.Count; j++)
                        {
                            double x = Convert.ToDouble(points[j].LastChild.PreviousSibling.InnerText);
                            double y = Convert.ToDouble(points[j].LastChild.InnerText);
                            poly.InnerRings[innerRingIndex].Vertices.Add(new Vertex(x, y));
                        }
                        poly.InnerRings[innerRingIndex].Vertices.Add(poly.InnerRings[innerRingIndex].Vertices[0]);
                    }
                }
            }
        }
    }
    else if (xdoc.ChildNodes[1].Name == “Ellipse”)
    {
        double width = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].InnerText);
        double height = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].InnerText);
        double centerX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[4].LastChild.PreviousSibling.InnerText);
        double centerY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[4].LastChild.InnerText);
        EllipseShape ellipseShape = new EllipseShape(new PointShape(centerX, centerY), width, height);
        returnMultiPolygonShape.Polygons.Add(ellipseShape.ToPolygon());
    }
    else if (xdoc.ChildNodes[1].Name == “StraightRectangle”)
    {
        double minX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].ChildNodes[2].InnerText);
        double maxY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[2].ChildNodes[3].InnerText);
        double maxX = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].ChildNodes[2].InnerText);
        double minY = Convert.ToDouble(xdoc.ChildNodes[1].ChildNodes[3].ChildNodes[3].InnerText);
        RectangleShape rectangleShape = new RectangleShape(minX, maxY, maxX, minY);
        returnMultiPolygonShape.Polygons.Add(rectangleShape.ToPolygon());
    }
    return returnMultiPolygonShape;
}

public static string GetXml(AreaBaseShape areaBaseShape)
{
    MultipolygonShape multiPolygonShape;
    if (areaBaseShape is PolygonShape)
    {
        multiPolygonShape = new MultipolygonShape();
        multiPolygonShape.Polygons.Add((PolygonShape)areaBaseShape);
    }
    else if (areaBaseShape is MultipolygonShape)
    {
        multiPolygonShape = (MultipolygonShape)areaBaseShape;
    }
    else
    {
        return “”;
    }

    StringBuilder sb = new StringBuilder();
    sb.AppendLine("<?xml version=&#34;1.0&#34;?>");
    sb.AppendLine("<Polygon xmlns:xsd=&#34;w3.org/2001/XMLSchema&#34; xmlns:xsi=&#34;w3.org/&#34;>");
    sb.AppendLine(string.Format("<Key>{0}", multiPolygonShape.Id));
    sb.AppendLine(string.Format("<Selected>false"));

    sb.AppendLine("<Parts>");
    foreach (PolygonShape polygonShape in multiPolygonShape.Polygons)
    {
        sb.AppendLine("<MultiPoint>");
        sb.AppendLine(string.Format("<Key>{0}", Guid.NewGuid().ToString()));
        sb.AppendLine(string.Format("<Selected>false"));
        sb.AppendLine(string.Format("<RingType>OuterRing"));
        sb.AppendLine(string.Format("<RingOrder>ClockWise")); // Need to determine the clockwise or anticlockwise.

        sb.AppendLine(string.Format("<Points>"));
        for (int i = 0; i < polygonShape.OuterRing.Vertices.Count - 1; i++)
        {
            Vertex vertex = polygonShape.OuterRing.Vertices[i];

            sb.AppendLine(string.Format("<PointShape>"));
            sb.AppendLine(string.Format("<Key>{0}", Guid.NewGuid().ToString()));
            sb.AppendLine(string.Format("<Selected>false"));
            sb.AppendLine(string.Format("<X>{0}", vertex.X));
            sb.AppendLine(string.Format("<Y>{0}", vertex.Y));
            sb.AppendLine(string.Format("</PointShape>"));
        }
        sb.AppendLine(string.Format(""));
        sb.AppendLine("");

        foreach (RingShape innerRing in polygonShape.InnerRings)
        {
            sb.AppendLine("<MultiPoint>");
            sb.AppendLine(string.Format("<Key>{0}", Guid.NewGuid().ToString()));
            sb.AppendLine(string.Format("<Selected>false"));
            sb.AppendLine(string.Format("<RingType>InnerRing"));
            sb.AppendLine(string.Format("<RingOrder>ClockWise")); // Need to determine the clockwise or anticlockwise.

            sb.AppendLine(string.Format("<Points>"));
            for (int i = 0; i < innerRing.Vertices.Count - 1; i++)
            {
                Vertex vertex = innerRing.Vertices[i];

                sb.AppendLine(string.Format("<PointShape>"));
                sb.AppendLine(string.Format("<Key>{0}", Guid.NewGuid().ToString()));
                sb.AppendLine(string.Format("<Selected>false"));
                sb.AppendLine(string.Format("<X>{0}", vertex.X));
                sb.AppendLine(string.Format("<Y>{0}", vertex.Y));
                sb.AppendLine(string.Format("</PointShape>"));
            }
            sb.AppendLine(string.Format(""));
            sb.AppendLine("");
        }
    }

    sb.AppendLine("");
    sb.AppendLine("</Polygon>");

    return sb.ToString();
}


Rob, 
  
   Sorry for not being so helpful on this.  I am really not up on the 2.x xml structure and everyone I ask around here is also a bit foggy on it.  I am going to forward this to one of our main 2.x guys.  We will get this for you, give me a day or two. 
  
 David

Thanks!

Rob, 
  
   I will let you know as soon as I hear back.  Also if I don’t hear back soon I will peruse the guy. 
  
 David

Any luck tracking down the guy?

Rob, 
  
 I’m very sorry that the guy is very busy these days preparing for the new release and he didn’t finish this XML parser. He will be capable to work back on this I think next week and we will let you know as soon as it is done. Sorry for the inconvenience. 
  
 Thanks, 
  
 Ben