using IStation.Epanet;
|
using IStation.Epanet.Enums;
|
using IStation.Epanet.Network.Structures;
|
using System.IO.Compression;
|
using System.Xml;
|
|
namespace IStation.Epanet.Network.IO.Input
|
{
|
|
public class XmlParser : InputParser
|
{
|
private SectType _sectionType;
|
private XmlReader _reader;
|
private readonly bool _gzipped;
|
|
public XmlParser(bool gzipped) { _gzipped = gzipped; }
|
|
private void LogException(ErrorCode err, string line)
|
{
|
if (err == ErrorCode.Ok)
|
return;
|
|
var ex = new InputException(err, _sectionType, line);
|
|
base.errors.Add(ex);
|
|
base.LogException(ex);
|
|
}
|
|
public override Network Parse(Network nw, string f)
|
{
|
net = nw ?? new Network();
|
|
XmlReaderSettings settings = new XmlReaderSettings
|
{
|
CloseInput = false,
|
ValidationType = ValidationType.None,
|
CheckCharacters = true,
|
IgnoreComments = false,
|
IgnoreWhitespace = true,
|
|
};
|
|
try
|
{
|
|
|
Stream stream = _gzipped
|
? (Stream)new GZipStream(File.OpenRead(f), CompressionMode.Decompress)
|
: File.OpenRead(f);
|
|
using (stream)
|
{
|
|
using (_reader = XmlReader.Create(stream, settings))
|
{
|
_reader.ReadToFollowing("network");
|
ParsePc(_reader);
|
}
|
|
stream.Position = 0;
|
|
using (_reader = XmlReader.Create(stream, settings))
|
{
|
_reader.ReadToFollowing("network");
|
|
while (_reader.Read())
|
{
|
if (_reader.NodeType != XmlNodeType.Element || _reader.IsEmptyElement)
|
continue;
|
|
try
|
{
|
_sectionType = (SectType)Enum.Parse(typeof(SectType), _reader.Name, true);
|
}
|
catch (ArgumentException)
|
{
|
continue;
|
}
|
|
|
var r = _reader.ReadSubtree();
|
|
switch (_sectionType)
|
{
|
case SectType.TITLE:
|
ParseTitle(r);
|
break;
|
|
case SectType.JUNCTIONS:
|
ParseJunction(r);
|
break;
|
|
case SectType.RESERVOIRS:
|
ParseReservoir(r);
|
break;
|
|
case SectType.TANKS:
|
ParseTank(r);
|
break;
|
|
case SectType.PIPES:
|
ParsePipe(r);
|
break;
|
|
case SectType.PUMPS:
|
ParsePump(r);
|
break;
|
|
case SectType.VALVES:
|
ParseValve(r);
|
break;
|
|
case SectType.CONTROLS:
|
ParseControl(r);
|
break;
|
|
case SectType.RULES:
|
ParseRule(r);
|
break;
|
|
case SectType.DEMANDS:
|
ParseDemand(r);
|
break;
|
|
case SectType.SOURCES:
|
ParseSource(r);
|
break;
|
|
case SectType.EMITTERS:
|
ParseEmitter(r);
|
break;
|
|
case SectType.PATTERNS:
|
case SectType.CURVES:
|
break;
|
|
case SectType.QUALITY:
|
ParseQuality(r);
|
break;
|
|
case SectType.STATUS:
|
ParseStatus(r);
|
break;
|
|
case SectType.ROUGHNESS:
|
// TODO add ParseRoughness
|
break;
|
|
case SectType.ENERGY:
|
ParseEnergy(r);
|
break;
|
|
case SectType.REACTIONS:
|
ParseReact(r);
|
break;
|
|
case SectType.MIXING:
|
ParseMixing(r);
|
break;
|
|
case SectType.REPORT:
|
ParseReport(r);
|
break;
|
|
case SectType.TIMES:
|
ParseTime(r);
|
break;
|
|
case SectType.OPTIONS:
|
ParseOption(r);
|
break;
|
|
case SectType.COORDINATES:
|
ParseCoordinate(r);
|
break;
|
|
case SectType.VERTICES:
|
ParseVertice(r);
|
break;
|
|
case SectType.LABELS:
|
ParseLabel(r);
|
break;
|
|
case SectType.BACKDROP:
|
// TODO add ParseRoughness
|
break;
|
|
case SectType.TAGS:
|
|
case SectType.END:
|
break;
|
// TODO add etc
|
}
|
}
|
}
|
}
|
}
|
catch (IOException)
|
{
|
throw new EnException(ErrorCode.Err302);
|
}
|
|
return net;
|
}
|
|
private void ParseTitle(XmlReader r)
|
{
|
|
int i = Constants.MAXTITLE;
|
|
while (r.ReadToFollowing("line") && i-- > 0)
|
{
|
string s = r.ReadString();
|
net.Title.Add(s);
|
}
|
}
|
|
private void ParseJunction(XmlReader r)
|
{
|
if (!r.ReadToDescendant("node"))
|
return;
|
|
// while (r.ReadToFollowing("node"))
|
|
do
|
{
|
string name = r.GetAttribute("name");
|
|
Node node = new Junction(name);
|
|
try
|
{
|
net.Nodes.Add(node);
|
}
|
catch (ArgumentException)
|
{
|
LogException(ErrorCode.Err215, name);
|
continue;
|
}
|
|
string el = r.GetAttribute("elevation");
|
|
if (string.IsNullOrEmpty(el))
|
{
|
LogException(ErrorCode.Err201, r.Value);
|
continue;
|
}
|
|
try
|
{
|
node.Elevation = XmlConvert.ToDouble(el);
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
|
string sx = r.GetAttribute("x");
|
string sy = r.GetAttribute("y");
|
|
if (!string.IsNullOrEmpty(sx) && !string.IsNullOrEmpty(sy))
|
{
|
try
|
{
|
node.Coordinate = new EnPoint(XmlConvert.ToDouble(sx), XmlConvert.ToDouble(sy));
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, node.Name);
|
continue;
|
}
|
}
|
|
|
using (var rr = r.ReadSubtree())
|
{
|
|
rr.Read();
|
|
while (rr.Read())
|
{
|
switch (rr.NodeType)
|
{
|
case XmlNodeType.Element:
|
|
if (rr.Name.Equals("demand", StringComparison.Ordinal))
|
{
|
string att = rr.GetAttribute("base");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
try
|
{
|
node.PrimaryDemand.Base = XmlConvert.ToDouble(att.Trim());
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
}
|
|
att = rr.GetAttribute("pattern");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
Pattern p = net.GetPattern(att.Trim());
|
if (p == null)
|
{
|
LogException(ErrorCode.Err205, name);
|
continue;
|
}
|
|
node.PrimaryDemand.Pattern = p;
|
}
|
|
}
|
else if (rr.Name.Equals("tag", StringComparison.Ordinal))
|
{
|
string s = rr.ReadString();
|
if (!string.IsNullOrEmpty(s)) node.Tag = s.Trim();
|
}
|
|
break;
|
|
case XmlNodeType.Comment:
|
node.Comment = rr.Value;
|
break;
|
}
|
}
|
}
|
|
} while (r.ReadToNextSibling("node"));
|
}
|
|
private void ParseReservoir(XmlReader r)
|
{
|
|
if (!r.ReadToDescendant("node"))
|
return;
|
|
// while (r.ReadToFollowing("node"))
|
|
do
|
{
|
string name = r.GetAttribute("name");
|
|
Tank node = new Tank(name);
|
|
try
|
{
|
net.Nodes.Add(node);
|
}
|
catch (ArgumentException)
|
{
|
LogException(ErrorCode.Err215, name);
|
continue;
|
}
|
|
string el = r.GetAttribute("elevation");
|
|
if (string.IsNullOrEmpty(el))
|
{
|
LogException(ErrorCode.Err201, r.Value);
|
continue;
|
}
|
|
try
|
{
|
node.Elevation = XmlConvert.ToDouble(el);
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
|
|
string pattern = r.GetAttribute("pattern");
|
|
if (!string.IsNullOrEmpty(pattern))
|
{
|
Pattern p = net.GetPattern(pattern.Trim());
|
if (p == null)
|
{
|
LogException(ErrorCode.Err205, name);
|
continue;
|
}
|
|
node.Pattern = p;
|
}
|
|
string sx = r.GetAttribute("x");
|
string sy = r.GetAttribute("y");
|
|
if (!string.IsNullOrEmpty(sx) && !string.IsNullOrEmpty(sy))
|
{
|
try
|
{
|
node.Coordinate = new EnPoint(XmlConvert.ToDouble(sx), XmlConvert.ToDouble(sy));
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, node.Name);
|
continue;
|
}
|
}
|
|
|
using (var rr = r.ReadSubtree())
|
{
|
|
rr.Read();
|
|
while (rr.Read())
|
{
|
switch (rr.NodeType)
|
{
|
case XmlNodeType.Element:
|
|
if (rr.Name.Equals("demand", StringComparison.Ordinal))
|
{
|
string att = rr.GetAttribute("base");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
try
|
{
|
node.PrimaryDemand.Base = XmlConvert.ToDouble(att.Trim());
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
}
|
|
att = rr.GetAttribute("pattern");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
Pattern p = net.GetPattern(att.Trim());
|
if (p == null)
|
{
|
LogException(ErrorCode.Err205, name);
|
continue;
|
}
|
|
node.PrimaryDemand.Pattern = p;
|
}
|
|
}
|
else if (rr.Name.Equals("tag", StringComparison.Ordinal))
|
{
|
string s = rr.ReadString();
|
if (!string.IsNullOrEmpty(s)) node.Tag = s.Trim();
|
}
|
|
break;
|
|
case XmlNodeType.Comment:
|
node.Comment = rr.Value;
|
break;
|
}
|
}
|
}
|
|
} while (r.ReadToNextSibling("node"));
|
|
}
|
|
private void ParseTank(XmlReader r)
|
{
|
|
if (!r.ReadToDescendant("node"))
|
return;
|
|
// while (r.ReadToFollowing("node"))
|
|
do
|
{
|
string name = r.GetAttribute("name");
|
|
Tank node = new Tank(name);
|
|
try
|
{
|
net.Nodes.Add(node);
|
}
|
catch (ArgumentException)
|
{
|
LogException(ErrorCode.Err215, name);
|
continue;
|
}
|
|
string el = r.GetAttribute("elevation");
|
|
|
|
if (string.IsNullOrEmpty(el))
|
{
|
// Reservour
|
string pattern = r.GetAttribute("pattern");
|
|
if (!string.IsNullOrEmpty(pattern))
|
{
|
// TODO
|
}
|
|
|
}
|
else
|
{
|
// Tank
|
// TODO
|
}
|
|
|
try
|
{
|
node.Elevation = XmlConvert.ToDouble(el);
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
|
string sx = r.GetAttribute("x");
|
string sy = r.GetAttribute("y");
|
|
if (!string.IsNullOrEmpty(sx) && !string.IsNullOrEmpty(sy))
|
{
|
try
|
{
|
node.Coordinate = new EnPoint(XmlConvert.ToDouble(sx), XmlConvert.ToDouble(sy));
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, node.Name);
|
continue;
|
}
|
}
|
|
|
using (var rr = r.ReadSubtree())
|
{
|
|
rr.Read();
|
|
while (rr.Read())
|
{
|
switch (rr.NodeType)
|
{
|
case XmlNodeType.Element:
|
|
if (rr.Name.Equals("demand", StringComparison.Ordinal))
|
{
|
string att = rr.GetAttribute("base");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
try
|
{
|
node.PrimaryDemand.Base = XmlConvert.ToDouble(att.Trim());
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, name);
|
continue;
|
}
|
}
|
|
att = rr.GetAttribute("pattern");
|
|
if (!string.IsNullOrEmpty(att))
|
{
|
Pattern p = net.GetPattern(att.Trim());
|
if (p == null)
|
{
|
LogException(ErrorCode.Err205, name);
|
continue;
|
}
|
|
node.PrimaryDemand.Pattern = p;
|
}
|
|
}
|
else if (rr.Name.Equals("tag", StringComparison.Ordinal))
|
{
|
string s = rr.ReadString();
|
if (!string.IsNullOrEmpty(s)) node.Tag = s.Trim();
|
}
|
|
break;
|
|
case XmlNodeType.Comment:
|
node.Comment = rr.Value;
|
break;
|
}
|
}
|
}
|
|
} while (r.ReadToNextSibling("node"));
|
|
}
|
|
private void ParsePipe(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParsePump(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseValve(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseControl(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseRule(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseDemand(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseSource(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseEmitter(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseQuality(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseStatus(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseEnergy(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseReact(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseMixing(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseReport(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseTime(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseOption(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseCoordinate(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseVertice(XmlReader r) { throw new NotImplementedException(); }
|
|
private void ParseLabel(XmlReader r) { throw new NotImplementedException(); }
|
|
|
private void ParsePc(XmlReader r)
|
{
|
_reader.ReadStartElement();
|
|
while (!r.EOF)
|
{
|
|
try
|
{
|
_sectionType = (SectType)Enum.Parse(typeof(SectType), r.Name, true);
|
}
|
catch (ArgumentException)
|
{
|
_sectionType = (SectType)(-1);
|
}
|
|
|
try
|
{
|
switch (_sectionType)
|
{
|
case SectType.PATTERNS:
|
ParsePattern(r.ReadSubtree());
|
break;
|
case SectType.CURVES:
|
ParseCurve(r.ReadSubtree());
|
break;
|
}
|
}
|
catch (InputException ex)
|
{
|
base.LogException(ex);
|
}
|
|
r.Skip();
|
|
}
|
|
if (errors.Count > 0)
|
throw new EnException(ErrorCode.Err200);
|
|
}
|
|
private void ParsePattern(XmlReader r)
|
{
|
|
if (!r.ReadToDescendant("pattern"))
|
return;
|
|
do
|
{
|
if (r.IsEmptyElement)
|
continue;
|
|
string name = r.GetAttribute("name");
|
|
if (string.IsNullOrEmpty(name))
|
continue;
|
|
var pat = new Pattern(name);
|
|
using (var rr = r.ReadSubtree())
|
{
|
rr.Read();
|
while (rr.Read())
|
{
|
switch (rr.NodeType)
|
{
|
case XmlNodeType.Element:
|
if (rr.Name.Equals("factor", StringComparison.Ordinal))
|
{
|
|
string s = rr.GetAttribute("value") ?? string.Empty;
|
|
try
|
{
|
pat.Add(XmlConvert.ToDouble(s));
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, rr.ReadInnerXml());
|
}
|
}
|
|
break;
|
|
case XmlNodeType.Comment:
|
pat.Comment = rr.Value;
|
break;
|
}
|
}
|
}
|
|
|
try
|
{
|
net.Patterns.Add(pat);
|
}
|
catch (ArgumentException)
|
{
|
LogException(ErrorCode.Err215, pat.Name);
|
}
|
|
|
} while (r.ReadToNextSibling("pattern"));
|
|
}
|
|
private void ParseCurve(XmlReader r)
|
{
|
|
if (!r.ReadToDescendant("curve"))
|
return;
|
|
do
|
{
|
if (r.IsEmptyElement)
|
continue;
|
|
string name = r.GetAttribute("name");
|
|
if (string.IsNullOrEmpty(name))
|
continue;
|
|
var cur = new Curve(name);
|
|
using (var rr = r.ReadSubtree())
|
{
|
rr.Read();
|
while (rr.Read())
|
{
|
switch (rr.NodeType)
|
{
|
case XmlNodeType.Element:
|
if (rr.Name.Equals("point", StringComparison.Ordinal))
|
{
|
|
string sx = rr.GetAttribute("x") ?? string.Empty;
|
string sy = rr.GetAttribute("y") ?? string.Empty;
|
|
try
|
{
|
cur.Add(XmlConvert.ToDouble(sx), XmlConvert.ToDouble(sy));
|
}
|
catch (FormatException)
|
{
|
LogException(ErrorCode.Err202, rr.ReadInnerXml());
|
}
|
}
|
|
break;
|
|
case XmlNodeType.Comment:
|
cur.Comment = rr.Value;
|
break;
|
}
|
}
|
}
|
|
try
|
{
|
net.Curves.Add(cur);
|
}
|
catch (ArgumentException)
|
{
|
LogException(ErrorCode.Err215, cur.Name);
|
}
|
|
} while (r.ReadToNextSibling("curve"));
|
|
r.ReadEndElement();
|
|
|
}
|
}
|
|
}
|