While loop jumps unexpectedly while reading XML - c#

I am reading an XML file using XMLDocument and XmlNodeReader.I do not know what happens to the while loop that it fails to run several parts of the code.
Here is my C# code:
public string TitleXml;
public string NameXml;
public string TypeXml;
public string ValueXml;
public Guid GuidXml;
public string DataString;
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(MyParent.xmlstring);
XmlNodeReader xreader = new XmlNodeReader(xdoc);
while (xreader.Read())
{
switch (xreader.Name)
{
case"GUID":
GuidXml = Guid.Parse(xreader.ReadInnerXml());
//after this break the name of the xreader changes.
break;
case "Type":
TypeXml = xreader.ReadInnerXml();
break;
case "Name":
NameXml = xreader.ReadInnerXml();
break;
case "Title":
TitleXml = xreader.ReadInnerXml();
break;
}
}
xreader.Close();
}
Here is my XML:
<Item>
<GUID>9A4FA56F-EAA0-49AF-B7F0-8CA09EA39167</GUID>
<Type>button</Type>
<Title>Save</Title>
<Value>submit</Value>
<Name>btnsave</Name>
<MaxLen>5</MaxLen>
</Item>

It doesn't exactly answer your question, but an (at least according to me) easier way of solving this would be:
XDocument doc = XDocument.Load("test.xml");
string TitleXml = doc.Descendants("Title").Single().Value;
string NameXml = doc.Descendants("Name").Single().Value;
string TypeXml = doc.Descendants("Type").Single().Value;
string ValueXml = doc.Descendants("Value").Single().Value;
Guid GuidXml = Guid.Parse(doc.Descendants("GUID").Single().Value);

I also think you should use Linq-to-XML, but for your example I'd explicitly list the elements, like so (compilable example program):
using System;
using System.Xml.Linq;
namespace ConsoleApplication1
{
internal class Program
{
static void Main()
{
string xml =
#"<Item>
<GUID>9A4FA56F-EAA0-49AF-B7F0-8CA09EA39167</GUID>
<Type>button</Type>
<Title>Save</Title>
<Value>submit</Value>
<Name>btnsave</Name>
<MaxLen>5</MaxLen>
</Item>";
XElement elem = XElement.Parse(xml);
Guid GuidXml = Guid.Parse(elem.Element("GUID").Value);
Console.WriteLine(GuidXml);
string TypeXml = elem.Element("Type").Value;
Console.WriteLine(TypeXml);
string NameXml = elem.Element("Name").Value;
Console.WriteLine(NameXml);
string TitleXml = elem.Element("Title").Value;
Console.WriteLine(TitleXml);
}
}
}

Related

During Xml deserialization, matrix is returning null

Got lots of trials to deserialize the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-down" compressionlevel="0" width="80" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="TilesetSA" tilewidth="16" tileheight="16" tilecount="4000" columns="80">
<image source="../../TilesetSA.png" width="1280" height="800"/>
</tileset>
<layer id="1" name="Walls" width="80" height="50">
<data encoding="csv">
3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,81,81,81,81,81,81,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,
</data>
</layer>
</map>
I don't have the opportunity to change the xml file, it must stay as is.
I Managed to retreive all attributes for "map", "tileset" and "image", but in the "layer" element, in can only retreive the attributes (id, name, width, height), the data element always remains null.
I created dedicated classes for "map", "tileset", "layer", "image" and "map".
Would anyone suggest me any code to solve this "null result" issue?
Use following xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication159
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string dataStr = (string)doc.Descendants("data").FirstOrDefault();
int[][] results = dataStr.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(y => int.Parse(y)).ToArray()).ToArray();
}
}
}
My code is as follow:
public virtual void WriteSaveXmlData(string pPath, int pRoom, bool pNewGame, int pX, int pY)
{
//xml save serialization
XmlSaving XmlGameSave = new XmlSaving();
XmlGameSave.SaveRootPath = pPath;
XmlGameSave.SavedCurrentRoom = pRoom;
XmlGameSave.XmlIsNewGame = pNewGame;
XmlGameSave.XHero = pX;
XmlGameSave.YHero = pY;
XmlSerializer xs = new XmlSerializer(typeof(XmlSaving));
using (StreamWriter wr = new StreamWriter(GameRound.GameSaveRootPath + GameRound.SaveFileName))
{
xs.Serialize(wr, XmlGameSave);
}
}
public virtual XmlSaving ReadSaveXmlData()
{
//xml save deserialization
XmlSerializer xs = new XmlSerializer(typeof(XmlSaving));
using (StreamReader rd = new StreamReader(GameRound.GameSaveRootPath + GameRound.SaveFileName))
{
XmlSaving XmlGameSave = xs.Deserialize(rd) as XmlSaving;
return XmlGameSave;
}
}
public virtual XmlMap ReadXmlMapData(string pPath, int RoomNumber)
{
XmlMap ReadTmxData = new XmlMap();
XmlSerializer TmxXmlMap = new XmlSerializer(typeof(XmlMap));
using (StreamReader rd = new StreamReader(pPath + #"P1\RoomMapSaphir0" + RoomNumber + ".tmx"))
{
ReadTmxData = TmxXmlMap.Deserialize(rd) as XmlMap;
return ReadTmxData;
}
}

How to read values from XML String from Web Service

my source like this in C#:
string xml = null;
WebRequest req = WebRequest.Create("https://www.freegeoip.net/xml");
req.Credentials = CredentialCache.DefaultCredentials;
WebResponse res = req.GetResponse();
Stream dataStream = res.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
xml = reader.ReadToEnd();
reader.Close();
res.Close();
am getting response like this :
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>
/// XMl Reponse END///////////////////////////////
I want pass parameters to Database like :
objLogDetails.IPAddress = ???? //Here i want to pass IP :162.158.50.10 from XMl string
HEre are two methods, one using xpath and the other using linq 2 xml:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace stackexchange
{
class Program
{
private static string theXml = #"<?xml version='1.0' encoding='UTF-8'?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>";
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(theXml);
XmlNode ip = xml.SelectSingleNode("/Response/IP");
Console.Out.WriteLine($"Ip Address: {ip.InnerText}");
XElement root = XElement.Parse(theXml);
XElement address = (from a in root.Descendants() where a.Name == "IP" select a).Single();
Console.Out.WriteLine($"Ip Address: {address.Value}");
}
}
}
What you can do here, is use an XElement to get items from the response and insert into your request.
You can do so like this:
//sets the node or remove
public static void SetOrRemoveNodeValue(XElement root, string xPath, string attributeName, string value)
{
XElement currentNode = root.XPathSelectElement(xPath);
if (currentNode != null)
{
if (currentNode.Attributes().FirstOrDefault(att => att.Name.LocalName.Equals(attributeName)) != null)
{
if (value == string.Empty)
{
currentNode.Attribute(attributeName).Remove();
}
else
{
currentNode.Attribute(attributeName).Value = value;
}
}
then use it like this:
Formatter.SetOrRemoveNodeValue("node", "your value type", "your value");
To extract value from the response, simply use:
currentNode.XPathSelectElement("//Response").Element("Ip").value;
Or simply
currentNode.XPathSelectElement("//Ip").value;
Trying This Code ..
private string mStrXMLStk = Application.StartupPath + "\\Path.xml";
private System.Xml.XmlDocument mXDoc = new XmlDocument();
mXDoc.Load(mStrXMLStk);
XmlNode XNode = mXDoc.SelectSingleNode("/Response");
if (XNode != null)
{
if (XNode != null)
{
int IntChildCount = XNode.ChildNodes.Count;
for (int IntI = 1; IntI <= 1; IntI++)
{
string LocalName = XNode.ChildNodes[IntI].LocalName;
XmlNode Node = mXDoc.SelectSingleNode("/Response/" + LocalName);
string _ip = Node.InnerText;
MessageBox.Show("IP" + _ip);
}
}
}
Completely worked

Determine if a Database is "Equal" to a DacPackage

Is there a way to use the SQL Server 2012 Microsoft.SqlServer.Dac Namespace to determine if a database has an identical schema to that described by a DacPackage object? I've looked at the API docs for DacPackage as well as DacServices, but not having any luck; am I missing something?
Yes there is, I have been using the following technique since 2012 without issue.
Calculate a fingerprint of the dacpac.
Store that fingerprint in the target database.
The .dacpac is just a zip file containing goodies like metadata, and
model information.
Here's a screen-grab of what you will find in the .dacpac:
The file model.xml has XML structured like the following
<DataSchemaModel>
<Header>
... developer specific stuff is in here
</Header>
<Model>
.. database model definition is in here
</Model>
</<DataSchemaModel>
What we need to do is extract the contents from <Model>...</Model>
and treat this as the fingerprint of the schema.
"But wait!" you say. "Origin.xml has the following nodes:"
<Checksums>
<Checksum Uri="/model.xml">EB1B87793DB57B3BB5D4D9826D5566B42FA956EDF711BB96F713D06BA3D309DE</Checksum>
</Checksums>
In my experience, this <Checksum> node changes regardless of a schema change in the model.
So let's get to it.
Calculate the fingerprint of the dacpac.
using System.IO;
using System.IO.Packaging;
using System.Security.Cryptography;
static string DacPacFingerprint(byte[] dacPacBytes)
{
using (var ms = new MemoryStream(dacPacBytes))
using (var package = ZipPackage.Open(ms))
{
var modelFile = package.GetPart(new Uri("/model.xml", UriKind.Relative));
using (var streamReader = new System.IO.StreamReader(modelFile.GetStream()))
{
var xmlDoc = new XmlDocument() { InnerXml = streamReader.ReadToEnd() };
foreach (XmlNode childNode in xmlDoc.DocumentElement.ChildNodes)
{
if (childNode.Name == "Header")
{
// skip the Header node as described
xmlDoc.DocumentElement.RemoveChild(childNode);
break;
}
}
using (var crypto = new SHA512CryptoServiceProvider())
{
byte[] retVal = crypto.ComputeHash(Encoding.UTF8.GetBytes(xmlDoc.InnerXml));
return BitConverter.ToString(retVal).Replace("-", "");// hex string
}
}
}
}
With this fingerprint now available, pseudo code for applying a dacpac can be:
void main()
{
var dacpacBytes = File.ReadAllBytes("<path-to-dacpac>");
var dacpacFingerPrint = DacPacFingerprint(dacpacBytes);// see above
var databaseFingerPrint = Database.GetFingerprint();//however you choose to do this
if(databaseFingerPrint != dacpacFingerPrint)
{
DeployDacpac(...);//however you choose to do this
Database.SetFingerprint(dacpacFingerPrint);//however you choose to do this
}
}
Here's what I've come up with, but I'm not really crazy about it. If anyone can point out any bugs, edge cases, or better approaches, I'd be much obliged.
...
DacServices dacSvc = new DacServices(connectionString);
string deployScript = dacSvc.GenerateDeployScript(myDacpac, #"aDb", deployOptions);
if (DatabaseEqualsDacPackage(deployScript))
{
Console.WriteLine("The database and the DacPackage are equal");
}
...
bool DatabaseEqualsDacPackage(string deployScript)
{
string equalStr = string.Format("GO{0}USE [$(DatabaseName)];{0}{0}{0}GO{0}PRINT N'Update complete.'{0}GO", Environment.NewLine);
return deployScript.Contains(equalStr);
}
...
What I really don't like about this approach is that it's entirely dependent upon the format of the generated deployment script, and therefore extremely brittle. Questions, comments and suggestions very welcome.
#Aaron Hudon answer does not account for post script changes. Sometimes you just add a new entry to a type table without changing the model. In our case we want this to count as new dacpac. Here is my modification of his code to account for that
private static string DacPacFingerprint(string path)
{
using (var stream = File.OpenRead(path))
using (var package = Package.Open(stream))
{
var extractors = new IDacPacDataExtractor [] {new ModelExtractor(), new PostScriptExtractor()};
string content = string.Join("_", extractors.Select(e =>
{
var modelFile = package.GetPart(new Uri($"/{e.Filename}", UriKind.Relative));
using (var streamReader = new StreamReader(modelFile.GetStream()))
{
return e.ExtractData(streamReader);
}
}));
using (var crypto = new MD5CryptoServiceProvider())
{
byte[] retVal = crypto.ComputeHash(Encoding.UTF8.GetBytes(content));
return BitConverter.ToString(retVal).Replace("-", "");// hex string
}
}
}
private class ModelExtractor : IDacPacDataExtractor
{
public string Filename { get; } = "model.xml";
public string ExtractData(StreamReader streamReader)
{
var xmlDoc = new XmlDocument() { InnerXml = streamReader.ReadToEnd() };
foreach (XmlNode childNode in xmlDoc.DocumentElement.ChildNodes)
{
if (childNode.Name == "Header")
{
// skip the Header node as described
xmlDoc.DocumentElement.RemoveChild(childNode);
break;
}
}
return xmlDoc.InnerXml;
}
}
private class PostScriptExtractor : IDacPacDataExtractor
{
public string Filename { get; } = "postdeploy.sql";
public string ExtractData(StreamReader stream)
{
return stream.ReadToEnd();
}
}
private interface IDacPacDataExtractor
{
string Filename { get; }
string ExtractData(StreamReader stream);
}

How do I differentiate types of XML files before deserializing?

I am loading MusicXML-files into my program. The problem: There are two “dialects”, timewise and partwise, which have different root-nodes (and a different structure):
<?xml version="1.0" encoding='UTF-8' standalone='no' ?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="2.0">
<work>...</work>
...
</score-partwise>
and
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE score-timewise PUBLIC "-//Recordare//DTD MusicXML 2.0 Timewise//EN" "http://www.musicxml.org/dtds/timewise.dtd">
<score-timewise version="2.0">
<work>...</work>
...
</score-timewise>
My code for deserializing the partwise score so far is:
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
var xmlSerializer = new XmlSerializer(typeof(ScorePartwise));
var result = (ScorePartwise)xmlSerializer.Deserialize(fileStream);
}
What would be the best way to differentiate between the two dialects?
Here's a way to do it by using an XDocument to parse the file, read the root element to determine the type, and read it into your serializer.
var xdoc = XDocument.Load(filePath);
Type type;
if (xdoc.Root.Name.LocalName == "score-partwise")
type = typeof(ScorePartwise);
else if (xdoc.Root.Name.LocalName == "score-timewise")
type = typeof(ScoreTimewise);
else
throw new Exception();
var xmlSerializer = new XmlSerializer(type);
var result = xmlSerializer.Deserialize(xdoc.CreateReader());
I would create both serializers
var partwiseSerializer = new XmlSerializer(typeof(ScorePartwise));
var timewiseSerializer = new XmlSerializer(typeof(ScoreTimewise));
Assuming that there is only these two I would call CanDeserialize method on one
using (var fileStream = new FileStream(openFileDialog.FileName, FileMode.Open))
{
using (var xmlReader = XmlReader.Create(filStream))
{
if (partwiseSerializer.CanDeserialize(xmlReader))
{
var result = partwiseSerializer.Deserialize(xmlReader);
}
else
{
var result = timewiseSerializer.Deserialize(xmlReader);
}
}
}
Obviously this is just an idea how to do it. If there were more options or according to your application design I would use a more sophisticated way to call CanDeserialize, but that method is the key in my opinion:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.candeserialize.aspx
The XmlReader class can be found here:
http://msdn.microsoft.com/en-us/library/System.Xml.XmlReader(v=vs.110).aspx
If you're concerned about resource usage:
internal const string NodeStart = "<Error ";
public static bool IsErrorDocument(string xml)
{
int headerLen = 1;
if (xml.StartsWith(Constants.XMLHEADER_UTF8))
{
headerLen += Constants.XMLHEADER_UTF8.Length;
}
else if (xml.StartsWith(Constants.XMLHEADER_UTF16))
{
headerLen += Constants.XMLHEADER_UTF16.Length;
}
else
{
return false;
}
if (xml.Length < headerLen + NodeStart.Length)
{
return false;
}
return xml.Substring(headerLen, NodeStart.Length) == NodeStart;
}
internal class Constants
{
public const string XMLHEADER_UTF16 = "<?xml version=\"1.0\" encoding=\"utf-16\"?>";
public const string XMLHEADER_UTF8 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
}

How to place DisplayName into Variable

I'm trying to do something, that may be extremely simple so please bear with me, I just want to get 'DisplayName' from an XML file into a string in my C# code. here's what I have:
THIS IS C#2.0 in VS2005
XML:
<MonitorScope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="System" xmlns="http://tempuri.org/XMLSchema.xsd">
<PersonalSafety>
<MonitorResponseRecord Enabled="false" DisplayName="ValveFailureAtCentralPosition">
<ExpressionMonitor>
<postAlarm>
<AlarmName>Valve_Position_Fault</AlarmName>
<Parameter1> Sensor Position = {X}</Parameter1>
<Parameter2> Sensor Position = {X}</Parameter2>
<Parameter3> Sensor Position = {X}</Parameter3>
</postAlarm>
</ExpressionMonitor>
</MonitorResponseRecord>
<MonitorResponseRecord ... ... ...>
... ...
... ... and so on about 1600 times.
In my C# code I've attempted the following but to No Avail:
C#:
public class AlarmRecord
{
/// <remarks/>
public string PmAlarm;
/// <remarks/>
public string Parameter1;
/// <remarks/>
public string Parameter2;
/// <remarks/>
public string Parameter3;
/// <remarks/>
public string DisplayName;
}
protected void OnPostAlarm(PostAlarm postAlarm)
{
try
{
AlarmRecord alarmRecord = new AlarmRecord();
alarmRecord.PmAlarm = postAlarm.AlarmName;
alarmRecord.Parameter1 = postAlarm.Parameter1;
alarmRecord.Parameter2 = postAlarm.Parameter2;
alarmRecord.Parameter3 = postAlarm.Parameter3;
string fileName = "UMSM.009.8Root.xml";
string fullPath;
fullPath = Path.GetFullPath(fileName);
XmlTextReader reader = new XmlTextReader(new StringReader(fullPath));
System.Xml.XPath.XPathDocument docNav = new System.Xml.XPath.XPathDocument(reader);
System.Xml.XPath.XPathNavigator Q = docNav.CreateNavigator();
System.Xml.XPath.XPathExpression EXE = Q.Compile("MonitorResponseRecord/#DisplayName");
alarmRecord.DisplayName = Convert.ToString(Q.Evaluate(EXE));
alarms.Enqueue( alarmRecord );
}
catch (Exception e)
{
Log.Write(e);
OnUnknownResponse(postAlarm);
}
}
basically my current issue is that durring Debug the issue that I'm noticing is in the line where 'reader' is initialized... the program usually throws an exception here
You could use an XmlReader:
protected void OnPostAlarm(PostAlarm postAlarm)
{
AlarmRecord record = null;
List<AlarmRecord> recordList = new List<AlarmRecord>();
using(XmlReader reader = XmlReader.Create("Xml/bin/UMSM.009.8Root.xml"))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "MonitorResponseRecord":
record = new AlarmRecord();
recordList.Add(record);
reader.MoveToAttribute("DisplayName");
record.DisplayName = reader.Value;
break;
case "AlarmName":
record.PmAlarm = reader.ReadString();
break;
case "Parameter1":
record.Parameter1 = reader.ReadString();
break;
case "Parameter2":
record.Parameter2 = reader.ReadString();
break;
case "Parameter3":
record.Parameter3 = reader.ReadString();
break;
}
}
}
}
Best to use XPathNavigator and XPath queries in .NET 2.0.
Reading attributes (like DisplayName in your example) is done by using # in your XPath query.
There's a decent example here. Although the XPathExpression bit isn't necessary, you could just call nav.Evaluate and provide the string XPath query directly.
Example XML (I needed to strip your namespace attributes):
<MonitorScope>
<PersonalSafety>
<MonitorResponseRecord Enabled="false" DisplayName="ValveFailureAtCentralPosition">
<ExpressionMonitor>
<postAlarm>
<AlarmName>Valve_Position_Fault</AlarmName>
<Parameter1> Sensor Position = {X}</Parameter1>
<Parameter2> Sensor Position = {X}</Parameter2>
<Parameter3> Sensor Position = {X}</Parameter3>
</postAlarm>
</ExpressionMonitor>
</MonitorResponseRecord>
</PersonalSafety>
Code example using XPath:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XPathNavigator nav = doc.CreateNavigator();
XPathNodeIterator nodeList = nav.Select("//MonitorScope/PersonalSafety/MonitorResponseRecord");
if (nodeList.Count != 0) {
foreach (XPathNavigator node in nodeList) {
// node queries are relative to MonitorResponseRecord node
string displayName = node.SelectSingleNode("./#DisplayName").Value;
string alarmName = node.SelectSingleNode("ExpressionMonitor/postAlarm/AlarmName").Value;
string param1 = node.SelectSingleNode("ExpressionMonitor/postAlarm/Parameter1").Value;
string param2 = node.SelectSingleNode("ExpressionMonitor/postAlarm/Parameter2").Value;
string param3 = node.SelectSingleNode("ExpressionMonitor/postAlarm/Parameter3").Value;
// do something with values
}
}

Categories

Resources