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;
}
}
Related
I have a very big xml file with below format
<ABC>
<NAMEDETAILS></NAMEDETAILS>
<PRODUCT>
<PRODUCTDETAILS>
<ProductName>
<name>Car</Name>
<name>lorry<name>
<name>Car<name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCTDETAILS>
<ProductName>
<name>van</Name>
<name>cycle</Name>
<name>bus</Name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCTDETAILS>
<ProductName>
<name>car</Name>
<name>cycle</Name>
<name>bus</Name>
</ProductName>
</PRODUCTDETAILS>
<PRODUCT>
</ABC>
I want to retrieve the PRODUCTDETAILS data whose name tag has the value "car" and save it in a new xml file. I am using XMLReader but i am stuck in moving forward. Can somebody help me. Below is the c# code
XMLReader xmlReader = XMLReader.Create(#"\\Drive\xmlfile.xml")
while (xmlReader.Read())
{
If (xmlReader.NodeType == XMLNodeType.Element) && (xmlReader.Name == "PRODUCTDETAILS")
{
xmlReader.ReadtoDescendant("ProductName")
}
}
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace ConApp1
{
class Program
{
static void Main()
{
using (var xmlWriter = XmlWriter.Create("result.xml"))
using (var xmlReader = XmlReader.Create("test.xml"))
{
xmlWriter.WriteStartElement("PRODUCT");
while (xmlReader.ReadToFollowing("PRODUCTDETAILS"))
{
using (var nodeReader = xmlReader.ReadSubtree())
{
nodeReader.MoveToContent();
var elem = (XElement)XNode.ReadFrom(nodeReader);
var name = elem.Descendants("name").First().Value;
if (name.Equals("car", StringComparison.OrdinalIgnoreCase))
{
elem.WriteTo(xmlWriter);
}
}
}
}
}
}
}
Since you say that the file is large, both reading and writing should be done using streaming tools. XmlWriter is used for writing. This guarantees low memory consumption and no OutOfMemoryException occurs.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.xml";
const string OUTPUT_FILENAME = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(INPUT_FILENAME);
string header = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Cars></Cars>";
XDocument doc = XDocument.Parse(header);
XElement cars = doc.Root;
while (!reader.EOF)
{
if (reader.Name != "PRODUCTDETAILS")
{
reader.ReadToFollowing("PRODUCTDETAILS");
}
if (!reader.EOF)
{
XElement product = (XElement)XElement.ReadFrom(reader);
if(product.Descendants("name").Any(x => ((string)x).Trim() == "Car"))
{
cars.Add(product);
}
}
}
doc.Save(OUTPUT_FILENAME);
}
}
}
While executing, I get the error at this location.
XDocument doc = XDocument.Parse(BuildIsoMessage.Properties.Resources.Deneme);//I Get the document from resources in this way.
` GenericPackager packager = new GenericPackager(doc.ToString());`
An unhandled exception of type 'org.jpos.iso.ISOException' occurred in jpos.dll.Additional information: Error reading <!DOCTYPE isopackager PUBLIC "-//jPOS/jPOS Generic Packager DTD 1.0//EN" "http://jpos.org/dtd/generic-packager-1.0.dtd"[]>
I am trying to build an ISO Message in c#. I converted Jar files into one dll file and using some of the namespaces
using org.jpos.util;
using org.jpos.iso;
using org.jpos.iso.channel;
using org.jpos.iso.packager;
however I can not pack my xml file, it throws an error.
https://github.com/jpos/jPOS/blob/master/jpos/src/main/resources/packager/iso87ascii.xml
Jpos dll worked fine when provided path like below
GenericValidatingPackager packager = new GenericValidatingPackager();
packager.readFile("c:/isoxml/iso8583binary.xml");
This is too simple to use a 3rd party dll. Use xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xmlHeader =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
"<!DOCTYPE isopackager PUBLIC" +
" \"-//jPOS/jPOS Generic Packager DTD 1.0//EN\"" +
" \"http://jpos.org/dtd/generic-packager-1.0.dtd\" >" +
"<!-- ISO 8583:1987 (ASCII) field descriptions for GenericPackager -->" +
"<isopackager>" +
"</isopackager>";
//<isofield
XDocument doc = XDocument.Parse(xmlHeader);
XElement isoPackager = doc.Descendants("isopackager").FirstOrDefault();
List<IsoField> isoFields = new List<IsoField>() {
new IsoField() { id= 0, length= 4, name="MESSAGE TYPE INDICATOR", cClass = "org.jpos.iso.IFA_NUMERIC"},
new IsoField() { id= 1, length= 16, name="BIT MAP", cClass= "org.jpos.iso.IFA_BITMAP"},
new IsoField() { id= 2, length= 19, name="PAN - PRIMARY ACCOUNT NUMBER", cClass= "org.jpos.iso.IFA_LLNUM"}
};
foreach (IsoField isofield in isoFields)
{
isoPackager.Add(new XElement("isofield", new object[] {
new XElement("id", isofield.id),
new XElement("length", isofield.length),
new XElement("name", isofield.name),
new XElement("class", isofield.cClass)
}));
}
doc.Save(FILENAME);
}
}
public class IsoField
{
public int id {get; set;}
public int length { get; set; }
public string name { get; set; }
public string cClass { get; set; }
}
}
The snippet below isn't summing the variables (int)winTemp and playerWIn. I've verified that both variables are assigned the correct value by printing to screen before calling createXML(). My theory is that you cannot evaluate equations while creating new XELEMENT's. Can anyone verify this?
new XElement("playerWin", (int)winTemp + playerWin),
If I do it outside of XElement, like the commented lines in saveXML(), it works as intended.
If the file did not exist - Excepted XML output should be Wins=10, Loss=1, Tie=0.
If the file was existed - Excepted XML output should be Wins=20, Loss=2, Tie=0.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
namespace Testing_LINQ_to_XML
{
class Program
{
static void Main()
{
Player p = new Player();
p.readXML();
p.toScreen();
p.saveXML();
p.readXML();
p.toScreen();
p.Exit();
}
}
public class Player
{
public string path;
public string playerName;
public int playerWin = 10;
public int playerLoss = 1;
public int playerTie = 0;
public int winTemp;
public int lossTemp;
public int tieTemp;
public Player()
{
Console.WriteLine("Enter player Name...");
playerName = Console.ReadLine();
Console.WriteLine("n: " + playerName);
getPath();
Console.WriteLine("p: " + path);
Console.ReadLine();
}
public string getPath()
{
path = (#"..\XML Saves\" + playerName + ".xml");
return path;
}
public void toScreen()
{
Console.WriteLine("\nYour Record Is:\n");
Console.WriteLine("Wins: " + playerWin);
Console.WriteLine("Losses: " + playerLoss);
Console.WriteLine("Ties: " + playerTie);
}
public void saveXML()
{
if (File.Exists(path))
{
readXML();
File.Delete(path);
//playerWin = (int)winTemp;
//playerLoss = (int)lossTemp;
//playerTie = (int)tieTemp;
createFile();
}
else
{
createFile();
}
}
public void createFile()
{
XDeclaration _obj = new XDeclaration("1.0", "utf-8", "");
XNamespace gameSaves = "gameSaves";
XElement fileNew = new XElement("Root",
new XElement("Player",
new XElement("playerName", playerName),
new XElement("Stats",
new XElement("playerWin", (int)winTemp + playerWin),
new XElement("playerLoss", (int)lossTemp + playerLoss),
new XElement("playerTie", (int)tieTemp + playerTie))));
fileNew.Save(path);
Console.WriteLine("Save created: " + path);
}
public void readXML()
{
if (File.Exists(path))
{
var winTemp = new XElement("playerWin", playerWin);
var lossTemp = new XElement("playerLoss", playerLoss);
var tieTemp = new XElement("playerTie", playerTie);
}
else
{
Console.WriteLine("\nYou don't have any stats to show yet. Get playing!!!");
}
}
public void Exit()
{
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
}
XML output:
<Root>
<Player>
<playerName>Name</playerName>
<Stats>
<playerWin>10</playerWin>
<playerLoss>1</playerLoss>
<playerTie>0</playerTie>
</Stats>
</Player>
</Root>
The locally scoped winTemp variable is hiding the instance variable (inside readXML() method). Thus winTemp instance variable does not get set at all and holds the default value, i.e. 0, by the time of addition.
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\"?>";
}
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);
}
}
}