I have a C# Web Service that is serializing my simple class:
[Serializable]
[XmlInclude(typeof(Bitmap))]
[XmlTypeAttribute(Namespace = "http://tempuri.org/")]
public class Class1
{
private static Bitmap _myImage = new Bitmap(#"C:\WebApplication1\ClassLibrary1\Untitled.png");
public Bitmap MyImage
{
get { return _myImage; }
set
{
_myImage = value;
}
}
}
Here's the asmx.cs code that does the serialization:
[WebMethod]
public string HelloWorld()
{
var c = new Class1();
XmlSerializer serializer = new XmlSerializer(typeof(Class1));
return XMLSerializer(c);
}
public string XMLSerializer(object pObject)
{
try
{
XmlSerializer xs = new XmlSerializer(pObject.GetType());
using (StringWriter stream = new StringWriter())
{
xs.Serialize(stream, pObject);
stream.Flush();
return stream.ToString();
}
}
catch (Exception ex)
{
return ex.ToString();
}
}
Looks prety straight forward. However, the XML generated by the XmlSerializer is producing and error when I try to DeSerialize it.
{"There is an error in XML document (5, 5)."}
{"Parameter is not valid."}
When I try to load the generated XML into IE I get this error.
Switch from current encoding to specified encoding not supported. Error processing resource 'file:///C:/Users/mhall15/Deskt...
<?xml version="1.0" encoding="utf-16"?>
Here's the generated XML:
<?xml version="1.0" encoding="utf-16"?>
<Class1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyImage xmlns="http://tempuri.org/">
<Palette />
</MyImage>
</Class1>
Any ideas what's going on?
During the serialization, replace "encoding="utf-16" with "encoding="utf-8"" and that will cut it. The source of the problem - I'm not sure, but I've ran into it numerous times, and that's how I dealt with it.
That's how to deal with the IE issue.
The deserialization should be amongst these lines. I'm posting the kind of arbitrary code I normally use:
public static object DeserializeFromXML<T>(string _input)
{
object _temp = Activator.CreateInstance<T>();
Type expected_type = _temp.GetType();
_temp = null;
XmlSerializer serializer = new XmlSerializer(expected_type);
StringReader stringWriter = new StringReader(_input);
object _copy = serializer.Deserialize(stringWriter);
return _copy;
}
In the above example, I'm using templating for reusability sake. You should be able to call the method by saying DeserializeFromXML < Class1 >(_xml_input) where xml input is the string. That will force the compiler to use the definition of the given class to deserialize the XML input. That way you wouldn't even have to change the encoding in the serialization. If it's also a case where you may or may not know the data type to deserialize with, you can use a strategy design pattern where you register the root type of the XML with it's associated generic type. Later on you can reference that registry and arbitrarily deserialize any XML input as long as the root type is registered. It's a trick i normally use as well. If more is needed on this, let me know, and I'll explain in detail.
In addition,if you are running IE 9, the new update to IE 9 makes it difficult to view XML. Press F12 - go to developer tools and change your browser mode to run as IE 8 instead of IE 9.
Related
I have an XML file which starts something like this:-
<?xml version="1.0" encoding="UTF-8"?>
<Deal xmlns="http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AccountingDate>2019-09-30</AccountingDate>
When I try to convert this object to XML like below, I get an error:-
private static void Prod_Error_Test()
{
string prodRequestXml = File.ReadAllText("ProdXml.xml");
var serializer = new XmlSerializer(typeof(Service.Deal));
Service.Deal request ;
var reader = new StringReader(prodRequestXml);
request = (Service.Deal)serializer.Deserialize(reader);
}
The Error Message is "There is an error in XML document (2, 2).". The Inner Exception Message is "<Deal xmlns='http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models'> was not expected."
Service.Deal is a WCF Proxy.So I may not be able to add any attributes. Can anyone suggest what to do here ?
Being a WCF proxy doesn't preclude adding attributes; in particular, it is usually a partial class, which means you can have your own separate file, with:
namespace Service
{
[XmlRoot("Deal", Namespace = "http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models")]
partial class Deal {}
}
But ultimately: if the type doesn't conveniently fit the XML: stop fighting it - create a new separate type that fits the XML and works well with XmlSerializer, and then map between the two types in your own code.
I'm relatively new to Unity and C#. Actually, I mainly look at application code and try to learn a little bit. And that's fun.
Now I've stumbled upon a problem.
I'm trying to read an XML file and continue using the data from it. That even works. But now I don't want to use all records of the XML file, but only those that have a certain ID.
Currently I do it like this:
public class Data
{
public frage[] fragen = new frage[0];
public Data () { }
public static void Write(Data data)
{
XmlSerializer serializer = new XmlSerializer(typeof(Data));
using (Stream stream = new FileStream (GameUtility.XmlFilePath, FileMode.Create))
{
serializer.Serialize(stream, data);
}
}
public static Data Fetch ()
{
return Fetch(out bool result);
}
public static Data Fetch(out bool result)
{
if (!File.Exists(GameUtility.XmlFilePath)) { result = false; return new Data(); }
XmlSerializer deserializer = new XmlSerializer(typeof(Data));
using (Stream stream = new FileStream(GameUtility.XmlFilePath, FileMode.Open))
{
var data = (Data)deserializer.Deserialize(stream);
result = true;
return data;
}
}
}
This causes, I think, that all data is stored in the corresponding variable (data). But now I want only those data sets to be transferred that have the ID 5. Is this possible with simple adjustments or do I have to think about everything?
My data set, which is created via XML, looks like this:
<?xml version="1.0"?>
<Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<fragen>
<frage>
<info>IRGENDEINTEXT1</info>
<antworten>
<antwort>
<info>1</info>
<korrekt>true</korrekt>
</antwort>
<antwort>
<info>2</info>
<korrekt>false</korrekt>
</antwort>
<antwort>
<info>3</info>
<korrekt>false</korrekt>
</antwort>
<antwort>
<info>4</info>
<korrekt>false</korrekt>
</antwort>
</antworten>
<id>5</id>
</frage>
<frage>
<info>IRGENDEINTEXT2</info>
<antworten>
<antwort>
<info>1</info>
<korrekt>false</korrekt>
</antwort>
<antwort>
<info>2</info>
<korrekt>false</korrekt>
</antwort>
<antwort>
<info>3</info>
<korrekt>false</korrekt>
</antwort>
<antwort>
<info>4</info>
<korrekt>true</korrekt>
</antwort>
</antworten>
<id>7</id>
</frage>
</fragen>
</Data>
Thank you - I hope my question is meaningful and not too unclear. Forgive my incorrect English.
You could have, but I would advise against reading only partial files all the time because that is a constant IO hit. Every time you would need to fetch a new question you get another read IO on the disk. Unless your set of questions is humongous (e.g. several hundred MB), you could read all data into your Data object at game start and then just add a helper function into your Data class that supplies you with the relevant information. E.g.
class Data {
private Frage[] fragen;
// Read a Frage by ID
public Frage QuestionById(string id) {
return this.fragen.First(it => it.id == id);
}
}
Same for the answers:
class Frage {
private Antwort[] antworten;
public Antwort GetCorrectAnswer() {
return antworten.First(it => it.korrekt);
}
}
Then in your game logic you can just call:
var aFrage = data.QuestionById("4711");
var anAntwort = aFrage.GetCorrectAnswer();
You could theoretically also use XPath to just select the XML nodes you need, but for this to work you would still need to load the whole XML document into memory in order to run your XPath over it (I'm unaware of any XPath implementation for .net that would work on streams). So you may as well just use your own data structure as I have laid out.
If you really need a huge data set and cannot load everything into memory, you should maybe look at some database solution, e.g. SQLite to store your data. This would allow you to do SQL DB queries and doesn't require you to load all the data into memory.
I agree with Jan Thomä. What you do is called deserialization (when you create an xml or json from an object you do a serialization). So you just create an object from your xml file (of course tecnically you need to read the file to deserialize it but, of course, you use a library to handle it). Once you got the data you should be able to change your object or create a modified copy with your correct data.
Usually I prefer json so I'm not sure how to do it with XmlSerializer library (link with an example in the edit part) but you should create a bean object that is a representation of your xml file
(example antwort is one of the basic object and it should have a int info variable and a korrekt boolean variable, while antworten is an object that only contains a List of antwort and so on until you reach your main object fragen that contains all your basic rappresentation of your xml bean to deserialize (to create a bean just declare your variables and Getter/Setters for those variables))
After that you just deserialize your xml as a Fragen instead of as a Data type and you can than change your object the easy way.
EDIT. To undestand it better just look the example here:
https://learn.microsoft.com/it-it/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=netframework-4.8
you got the xml and the class that representate the object OrderedItem (note: the namespace should be optional but you need to call the variable with the same name of the variable in your xml and you should need getter and setter in OrderedItem class). Once you got OrderedItem item it's easy to read/write new value to the object, serialize a new xml with new data or just create a modified copy of your object.
You should just do the same thing.
Example from the link:
using System;
using System.IO;
using System.Xml.Serialization;
// This is the class that will be deserialized.
public class OrderedItem
{
[XmlElement(Namespace = "http://www.cpandl.com")]
public string ItemName;
[XmlElement(Namespace = "http://www.cpandl.com")]
public string Description;
[XmlElement(Namespace="http://www.cohowinery.com")]
public decimal UnitPrice;
[XmlElement(Namespace = "http://www.cpandl.com")]
public int Quantity;
[XmlElement(Namespace="http://www.cohowinery.com")]
public decimal LineTotal;
// A custom method used to calculate price per item.
public void Calculate()
{
LineTotal = UnitPrice * Quantity;
}
}
public class Test
{
public static void Main()
{
Test t = new Test();
// Read a purchase order.
t.DeserializeObject("simple.xml");
}
private void DeserializeObject(string filename)
{
Console.WriteLine("Reading with Stream");
// Create an instance of the XmlSerializer.
XmlSerializer serializer =
new XmlSerializer(typeof(OrderedItem));
// Declare an object variable of the type to be deserialized.
OrderedItem i;
using (Stream reader = new FileStream(filename, FileMode.Open))
{
// Call the Deserialize method to restore the object's state.
i = (OrderedItem)serializer.Deserialize(reader);
}
// Write out the properties of the object.
Console.Write(
i.ItemName + "\t" +
i.Description + "\t" +
i.UnitPrice + "\t" +
i.Quantity + "\t" +
i.LineTotal);
}
}
xml
<?xml version="1.0"?>
<OrderedItem xmlns:inventory="http://www.cpandl.com" xmlns:money="http://www.cohowinery.com">
<inventory:ItemName>Widget</inventory:ItemName>
<inventory:Description>Regular Widget</inventory:Description>
<money:UnitPrice>2.3</money:UnitPrice>
<inventory:Quantity>10</inventory:Quantity>
<money:LineTotal>23</money:LineTotal>
</OrderedItem>
i wrote an application which is a custom console that allows execution of various commands. One of the commands allows serialization of data. The input data is a string, which is a list of comma separated values.
My question is - how to make the serialized data compact as much as possible?
The serialization format is not important for me.
Here is the command's code:
using CustomConsole.Common;
using System.IO;
using System.Xml.Serialization;
using System;
namespace Shell_Commander.Commands
{
public class SerializeCommand : ICommand
{
private string _serializeCommandName = "serialize";
public string Name { get { return this._serializeCommandName; } set { _serializeCommandName = value; } }
public string Execute(string parameters)
{
try
{
var splittedParameters = parameters.Split(" ");
var dataToSerialize = splittedParameters[0].Split(",");
var pathTofile = splittedParameters[1].Replace(#"\", #"\\");
XmlSerializer serializer = new XmlSerializer(dataToSerialize.GetType());
using (StreamWriter writer = new StreamWriter(pathTofile))
{
serializer.Serialize(writer, dataToSerialize);
var length = new FileInfo(pathTofile).Length;
Console.WriteLine($"Wrote file to: {pathTofile}");
return length.ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e);
return "0";
}
}
}
}
The command accepts 2 parameters:
Data to serialize
File path (in order to save the serialized data).
Example - for the "1,2,4" input, the following file will be saved:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>1</string>
<string>2</string>
<string>4</string>
</ArrayOfString>
EDIT:
I want my command to be able to serialize also complex objects in the future, so writing the string as is to the file is not a solution.
I want to use only standard serialization methods and formats.
This question has been asked a lot of times on SO, but neither solution helped me.
My datastruct is serialized into an XML file using dataContractSerializer. The (de)serialization code is the following:
public static void serialize<T>(T xObject, string xFilePath, string xIndent = "")
{
XmlWriterSettings xSettings = ( xIndent == "" ? new XmlWriterSettings {Indent = false } : new XmlWriterSettings { Indent = true, IndentChars = xIndent } );
using (XmlWriter xStream = XmlWriter.Create(xFilePath, xSettings))
new DataContractSerializer(typeof(T)).WriteObject(xStream, xObject);
}
public static T deserialize<T>(string xFilePath)
{
using (FileStream xStream = new FileStream(xFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
DataContractSerializer xSerializer = new DataContractSerializer(typeof(T));
return (T)xSerializer.ReadObject(xStream);
}
}
A snippet of the written XML is
<?xml version="1.0" encoding="utf-8"?>
<PxePriceListEod xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="libTypes.salesApp">
<DateOfValidity xmlns:d2p1="libTypes">
<d2p1:_x002E_>2016-09-09T00:00:00</d2p1:_x002E_>
</DateOfValidity>
<PriceRecords>
<AbstractPxePriceRecordEod i:type="PxePriceRecordEodBal">
<Product xmlns:d4p1="libTypes">
<d4p1:Ccy>
<d4p1:_x002E_>EUR</d4p1:_x002E_>
</d4p1:Ccy>
<d4p1:Commodity>
<d4p1:_x002E_>Electricity</d4p1:_x002E_>
</d4p1:Commodity>
<d4p1:Duration>
<d4p1:_x002E_>Month</d4p1:_x002E_>
</d4p1:Duration>
<d4p1:Exchange>
<d4p1:_x002E_>Pxe</d4p1:_x002E_>
</d4p1:Exchange>
<d4p1:Period>
<d4p1:_x002E_>9</d4p1:_x002E_>
</d4p1:Period>
<d4p1:Type>
<d4p1:_x002E_>Base</d4p1:_x002E_>
</d4p1:Type>
<d4p1:Year>
<d4p1:_x002E_>2016</d4p1:_x002E_>
</d4p1:Year>
</Product>
<IsDeduced xmlns:d4p1="libTypes">
<d4p1:_x002E_>false</d4p1:_x002E_>
</IsDeduced>
<IsInterpolated xmlns:d4p1="libTypes">
<d4p1:_x002E_>false</d4p1:_x002E_>
</IsInterpolated>
<IsSynthetic xmlns:d4p1="libTypes">
<d4p1:_x002E_>false</d4p1:_x002E_>
</IsSynthetic>
<Price xmlns:d4p1="libTypes">
<d4p1:_x002E_>30.45</d4p1:_x002E_>
</Price>
<DateOfValidity xmlns:d4p1="libTypes">
<d4p1:_x002E_>2016-09-09T00:00:00</d4p1:_x002E_>
</DateOfValidity>
</AbstractPxePriceRecordEod>
... more AbstractPxePriceRecordEod elements ...
</PriceRecords>
</PxePriceListEod>
Features of the problem:
The error points to Line=0, Position=1 (which does not make sense)
There is no element with name containing "."
All classes that make it into the file are properly decorated with DataContract
The XML file is checked to really be in UTF-8 encoding (when read by Notepad++) and none of the other versions of (de)serializing code listed on SO (that implicitly specify UTF-8 encoding) helped
I know the file is ugly (autogenerated element names like "d4p1:x002E" - Im the only dev in this company and unfortunately I dont have time to nicely decorate 100+ classes)
Everything was working fine for 2.5 years, the problems started today.
Any hint is much appreciated,
Daniel
UPDATE
I have added a minimal amount of code that reproduces the problem here. The application tries to read the given class from an xml file, the classes that have the problematic dataContractNames are located in library\+support\+qprimitive.
_x002E_ is how XmlConvert.EncodeLocalName() encodes the string ".". See https://dotnetfiddle.net/phUYO3 for a demonstration. So you either:
Have a data member with "." as its name.
Have implemented IXmlSerializable and are writing elements with this name.
That being said, making a data contract type with [DataMember(Name = ".")] on one of the data members does not cause problems for me. I.e. I can serialize and deserialize the following successfully:
[DataContract(Namespace = "libTypes.salesApp")]
public class PxePriceListEod
{
[DataMember]
public DateOfValidity DateOfValidity { get; set; }
}
// DateOfValidity
[DataContract(Namespace = "libTypes")]
public class DateOfValidity
{
[DataMember(Name = ".")]
public DateTime DateTime { get; set; }
}
Okay this one DID it! Thanks to all of you!
public class Result
{
public String htmlEscaped
{
set;
get;
}
[XmlIgnore]
public String htmlValue
{ set; get; }
[XmlElement("htmlValue")]
public XmlCDataSection htmlValueCData
{
get
{
XmlDocument _dummyDoc = new XmlDocument();
return _dummyDoc.CreateCDataSection(htmlValue);
}
set { htmlValue = (value != null) ? value.Data : null; }
}
}
Result r = new Result();
r.htmlValue = ("<b>Hello</b>");
r.htmlEscaped = ("<b>Hello</b>");
XmlSerializer xml = new XmlSerializer(r.GetType());
TextWriter file = new StreamWriter(Environment.CurrentDirectory + "\\results\\result.xml", false, System.Text.Encoding.Default);
xml.Serialize(file, r);
file.Close();
RESULT:
<?xml version="1.0" encoding="Windows-1252"?>
<Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<htmlEscaped><b>Hello</b></htmlEscaped>
<htmlValue><![CDATA[<b>Hello</b>]]></htmlValue>
</Result>
As you can see, after CDATA is return type, no more escaped html in XML file on filesystem.
The JSON Serialization isn't working anymore, but this can be fixed with a little type extention.
QUESTION WAS:
Maybe someone knows how to make do it...
I have this Class:
public class Result
{
public String htmlValue
{
get;
set;
}
}
I use this to serialize it to XML
Result res = new Result();
res.htmlValue = "<p>Hello World</p>";
XmlSerializer s = new XmlSerializer(res.GetType());
TextWriter w = new StreamWriter(Environment.CurrentDirectory + "\\result.xml", false, System.Text.Encoding.Default);
s.Serialize(w, res);
w.Close();
Works fine i get this:
<?xml version="1.0" encoding="Windows-1252"?>
<Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<htmlValue><b>Hello World</b></htmlValue>
</Result>
What can do i have to change to get this:
<?xml version="1.0" encoding="Windows-1252"?>
<Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<htmlValue><![CDATA[<b>Hello World</b>]]></htmlValue>
</Result>
I've already searched but I can't find anything. The type of htmlValue
have to stay String, because of other Serialisations JSON, etc.
Tricky one... Thanks in advance for suggestions
HTML is correct in String within C#. Why decode or encode?
XmlSerializer saved the HTML escaped to XML file.
Don't use C# for consuming.
Is external tool which accept this:
<htmlValue><![CDATA[<b>Hello World</b>]]></htmlValue>
but not
<htmlValue><b>Hello World</b></htmlValue>
I do the same with JSON Serializer, in file on hard drive the HTML is saved correct.
Why and where to use HTTP Utility to prevent that? And how to get <![CDATA[ ]]> around it.
Can you give a code sample?
Are there any other Serializer than the C# own one?
I've found this Link .NET XML Serialization of CDATA ATTRIBUTE from Marco André Silva, which does I need to do, but it's different, how to include this without changing Types?
Here's a simple trick to do achieve what you want. You just need to serialize a XmlCDataSection property instead of the string property :
(it's almost the same as John's suggestion, but a bit simpler...)
public class Result
{
[XmlIgnore]
public String htmlValue
{
get;
set;
}
private static XmlDocument _dummyDoc;
[XmlElement("htmlValue")]
public XmlCDataSection htmlValueCData
{
get { return _dummyDoc.CreateCDataSection(htmlValue); }
set { htmlValue = (value != null) ? value.Data : null; }
}
}
See "CDATA serialization with XMLSerializer" for the same problem, and for the solution.
BTW, it seems to me that if the vendor no longer exists, it's time to use a different product. Possibly one that understands the XML specifications which have only existed for over a decade.
It is my understanding that you need the XML to feed it to some utility. Do you also plan to use it to de-serialize the object?
If not then why do not do it yourself - serialize your object that is? Roundtrip object -> XML -> object is somewhat tricky, but the first part is not.