StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
XmlSerializer serializer = new XmlSerializer(typeof(OpenShipments));
var ns = new XmlSerializerNamespaces();
ns.Add("x-schema:", #"x-schema:C:\UPSLabel\OpenShipments.xdr");
serializer.Serialize(writer, OS, ns);
xmlString = sb.ToString();
getting error object reference not found because i add namespace programatically.
basically in my xml namespace will look like below one
<OpenShipments xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr">
here i add the line ns.Add("x-schema:", #"x-schema:C:\UPSLabel\OpenShipments.xdr");
and for the above line i am getting error....what is my mistake. just can not figure out. please help me to construct the namespace.
Try like this:
var sb = new StringBuilder();
var myns = #"x-schema:C:\UPSLabel\OpenShipments.xdr";
using (var writer = XmlWriter.Create(sb))
{
var serializer = new XmlSerializer(typeof(OpenShipments), myns);
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, myns);
serializer.Serialize(writer, OS, ns);
xmlString = sb.ToString();
}
will generate:
<OpenShipments xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr">
...
</OpenShipments>
The line:
ns.Add("x-schema:", #"x-schema:C:\UPSLabel\OpenShipments.xdr");
is adding an alias, i.e. allowing the serializer to use x-schema: inside the xml. However this doesn't make your object use this namespace; for that, you need (on your type):
[XmlRoot(Namespace=#"x-schema:C:\UPSLabel\OpenShipments.xdr")]
public class OpenShipments {...}
(or something equivalent, perhaps using XmlAttributeOverrides)
Note that with the alias added, you will get:
<x-schema:OpenShipments xmlns:x-schema="x-schema:C:\UPSLabel\OpenShipments.xdr" />
To get it without an alias, you want:
ns.Add("", #"x-schema:C:\UPSLabel\OpenShipments.xdr");
which gives output:
<OpenShipments xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr" />
Related
After Serialzation, object to a string
I am getting the current xml
<obj>
...
<field p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance"/>
...
</obj>
the field is nullable so i am waiting for an xsi:nill,
instead i am getting p2:nill why?
When building an XmlSerializer you can control the namespaces, if you don't random(ish) names will be applied. Try seeing if something like this helps
var ns = new XmlSerializerNamespaces();
ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
var ser = new XmlSerializer(typeof(AnEntity));
ser.Serialize(Console.Out, new AnEntity(), ns);
I am serialising an object to XML and I get the output like so :
<?xml version="1.0" encoding="utf-8"?>
<SOrd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
However I would like it to be like so :
<SOrd xmlns:SOrd="http://..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://....xsd">
How can I do this?
I have tried adding attributes to the root object before serialisation and also this :
XmlSerializerNamespaces xmlNameSpace = new XmlSerializerNamespaces();
xmlNameSpace.Add("xmlns:SOrd", "http://...");
xmlNameSpace.Add("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
xmlNameSpace.Add("xsi:schemaLocation", "http://....xsd");
XmlSerializer xs = new XmlSerializer(ord.GetType());
TextWriter writer = new StreamWriter(outputPath, false);
xs.Serialize(writer, ord, xmlNameSpace);
writer.Close();
But I get the exception "The ':' character, hexadecimal value 0x3A, cannot be included in a name."
the prefic can't contain the ":", take out the first part xmlns:
here is your code slighly changed:
XmlSerializerNamespaces xmlNameSpace = new XmlSerializerNamespaces();
xmlNameSpace.Add("SOrd", "http://...");
xmlNameSpace.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
xmlNameSpace.Add("schemaLocation", "http://....xsd");
XmlSerializer xs = new XmlSerializer(ord.GetType());
TextWriter writer = new StreamWriter(outputPath, false);
xs.Serialize(writer, ord, xmlNameSpace);
writer.Close();
make sure to add the required attributes for each class since the serialization attributes are not inhereted. for more about the inheretence of attributes check: How to deserialize concrete implementation of abstract class from XML
EDIT
you can achieve the xsi:shcemaLocation Like that:
[XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar", DataType = "schemaLocation")]
public class Foo
{
[System.Xml.Serialization.XmlAttributeAttribute(AttributeName = "schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string schemaLocation = "http://example";
}
I feel like I am going made. I have written a hundred deserializing routines, but this one is killing me!
Below is what I get returned from a service. A very simple array of strings...I think.
<ArrayOfstring xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<string>Action & Adventure</string>
<string>Comedy</string>
<string>Drama</string>
<string>Family</string>
<string>Horror</string>
<string>Independent & World</string>
<string>Romance</string>
<string>Sci-Fi/Fantasy</string>
<string>Thriller & Crime</string>
</ArrayOfstring>
I am using out the box deserializing
var serializer = new XmlSerializer(typeof(List<string>));
var reader = new StringReader(xmlString);
var GenreList = (List<string>)serializer.Deserialize(reader);
but I get the following error on the Deserialize line:
<ArrayOfstring xmlns='http://schemas.microsoft.com/2003/10/Serialization/Arrays'> was not expected
I have tried including the namespace and creating all manner of exotic objects in an attempt to get this to work. Crazy amount of time. In the end I have requested it in JSON and deserialised that with Json.net.
However I am curious as to what I have been doing wrong!
Of course XmlSerializer can deserialize it. All you need is to create XmlSerializer as follows
var serializer = new XmlSerializer(typeof(List<string>),
new XmlRootAttribute() { ElementName = "ArrayOfstring", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays" });
The XML Serializer cannot deserialize a simpletype or a list of simple types without additional specification, but the DataContractReader can:
string content = #"
<ArrayOfstring xmlns=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<string>Action & Adventure</string>
<string>Comedy</string>
<string>Drama</string>
<string>Family</string>
<string>Horror</string>
<string>Independent & World</string>
<string>Romance</string>
<string>Sci-Fi/Fantasy</string>
<string>Thriller & Crime</string>
</ArrayOfstring>";
var serializer = new DataContractSerializer(typeof(string[]));
var reader = new XmlTextReader(new StringReader(content));
var GenreList = new List<string>((string[])serializer.ReadObject(reader));
You can also use a simple class to achieve the same results. Note that I removed the namespaces from your XML file for brevity. You can implement reading of the namespaces in the serializer if you please.
public class ArrayOfstring
{
[XmlElement("string")]
public List<string> strings;
}
private void Deserialize(string xmlString)
{
var serializer = new XmlSerializer(typeof(ArrayOfstring));
var reader = new StringReader(xmlString);
var GenreList = ((ArrayOfstring) serializer.Deserialize(reader)).strings;
}
This will work
DataContractSerializer xmlSer = new DataContractSerializer(typeof(string[]));
TextReader reader=new StreamReader(xmlString);
var stringArr= (string[])xmlSer.ReadObject(reader);
List<string> listStr=new List<>();
for(var s in stringArr)
{
listStr.Add(s);
}
I realize this is an old question, but I recently ran on to the same issue and wanted to share what worked for me. I tried all the approaches outlined as potential solutions, but couldn't get any of them to work. Even specifying the namespace in the XmlRootAttribute approach would throw the "was not expected" error reported in the original problem. I was getting the ArrayOfString as a response from an API, so I used an XDocument parse approach:
List<string> lstGenre = new List<string>();
var response = await client.PostAsync(url, content);
var responseString = await response.Content.ReadAsStringAsync();
XDocument xdoc = XDocument.Parse(responseString);
XNamespace ns = xdoc.Root.GetDefaultNamespace();
XElement root = xdoc.Element(XName.Get("ArrayOfString", ns.NamespaceName));
IEnumerable<XElement> list = root.Elements();
foreach (XElement element in list)
{
string item = element.Value; // <-- individual strings from the "ArrayOfString"
lstGenre.Add(item);
}
I have an xml string which is very long in one line. I would like to save the xml string to a text file in a nice indent format:
<root><app>myApp</app><logFile>myApp.log</logFile><SQLdb><connection>...</connection>...</root>
The format I prefer:
<root>
<app>myApp</app>
<logFile>myApp.log</logFile>
<SQLdb>
<connection>...</connection>
....
</SQLdb>
</root>
What are .Net libraries available for C# to do it?
This will work for what you want to do ...
var samp = #"<root><app>myApp</app><logFile>myApp.log</logFile></root>";
var xdoc = XDocument.Load(new StringReader(samp), LoadOptions.None);
xdoc.Save(#"c:\temp\myxml.xml", SaveOptions.None);
Same result with System.Xml namespace ...
var xdoc = new XmlDocument();
xdoc.LoadXml(samp);
xdoc.Save(#"c:\temp\myxml.xml");
I'm going to assume you don't mean that you have a System.String instance with some XML in it, and I'm going to hope you don't create it via string manipulation.
That said, all you have to do is set the proper settings when you create your XmlWriter:
var sb = new StringBuilder();
var settings = new XmlWriterSettings {Indent = true};
using (var writer = XmlWriter.Create(sb, settings))
{
// write your XML using the writer
}
// Indented results available in sb.ToString()
Just another option:
using System.Xml.Linq;
public string IndentXmlString(string xml)
{
XDocument doc = XDocument.Parse(xml);
return doc.ToString();
}
I have a situation where I have an xml file that I don't want to modify.
The AddAnnotation function in XElement class provides an option to add memory-only data which is not serialized and not part of the XML.
I want to be able to save these annotations (for example: to another xml file) and then to deserialize both the xml and the annotations in order to get the same object I had.
I don't want to change the original xml and that's the reason that I use annotations.
To summarize, I want to be able to add custom data to an xml file. This data won't be a part of the xml when I serialize it or it will be a part of the xml but I would be able to retrieve the original xml easily.
Do you have any recommendation how I can do such a thing?
Edit: Should I use xml processing instructions? Are processing instructions intended for this kind of usage?
It sounds to me like the simplest approach would be to use regular nodes, but in a different xml namespace - i.e.
<foo standardAttrubute="abc" myData:customAttribute="def">
<standardElement>ghi</standardElement >
<myData:customElement>jkl</myData:customElement>
</foo>
(where myData is an xmlns alias for the namespace-uri)
In many cases, readers are only checking for data in their namespace (or the default/blank namespace) - values in custom namespaces are generally skipped.
To get pack the original xml, one simple approach would be to run it through an xslt that only respects the default/original namespace.
XNamespace myData = XNamespace.Get("http://mycustomdata/");
XElement el = new XElement("foo",
new XAttribute(XNamespace.Xmlns + "myData", myData.NamespaceName),
new XAttribute("standardAttribute", "abc"),
new XAttribute(myData + "customAttribute", "def"),
new XElement("standardElement", "ghi"),
new XElement(myData + "customAttribute", "jkl"));
string s = el.ToString();
To remove such data from an XElement, perhaps:
static void Strip(XElement el, XNamespace ns) {
List<XElement> remove = new List<XElement>();
foreach (XElement child in el.Elements()) {
if (child.Name.Namespace == ns) {
remove.Add(child);
} else {
Strip(child, ns);
}
}
remove.ForEach(child => child.Remove());
foreach (XAttribute child in
(from a in el.Attributes()
where a.Name.Namespace == ns
select a).ToList()) {
child.Remove();
}
}
The original question used the word "Serialize" but then also mentioned XElement and annotation. To me these are two different things.
If you really want to use the XmlSerializer:
What I would do is use XmlAttributeOverrides, to differentiate the serialization.
With the XmlAttributeOverrides you can programmatically, at runtime, override the xml serialization attributes that decorate your types.
Within your type, you can have a field/property that is intended to hold the annotation/documentation. Decorate that with XmlIgnore. Then, create one instance of the XmlSerializer that accepts no overrides. The annotation will not be serialized or de-serialized. Create another instance of the XmlSerializer for that type, using an XmlAttributeOverrides object. Specify an override for the XmlIgnore'd property (use XmlElementAttribute), as well as overrides for any attributes on any of the other members (use XmlIgnore=true).
Serialize the instance twice, one with each serializer.
Edit: here's the code:
public class DTO
{
[XmlIgnore]
public string additionalInformation;
[XmlElement(Order=1)]
public DateTime stamp;
[XmlElement(Order=2)]
public string name;
[XmlElement(Order=3)]
public double value;
[XmlElement(Order=4)]
public int index;
}
public class OverridesDemo
{
public void Run()
{
DTO dto = new DTO
{
additionalInformation = "This will bbe serialized separately",
stamp = DateTime.UtcNow,
name = "Marley",
value = 72.34,
index = 7
};
// ---------------------------------------------------------------
// 1. serialize normally
// this will allow us to omit the xmlns:xsi namespace
var ns = new XmlSerializerNamespaces();
ns.Add( "", "" );
XmlSerializer s1 = new XmlSerializer(typeof(DTO));
var builder = new System.Text.StringBuilder();
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
Console.WriteLine("\nSerialize using the in-line attributes: ");
using ( XmlWriter writer = XmlWriter.Create(builder, settings))
{
s1.Serialize(writer, dto, ns);
}
Console.WriteLine("{0}",builder.ToString());
Console.WriteLine("\n");
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// 2. serialize with attribute overrides
// use a non-empty default namespace
ns = new XmlSerializerNamespaces();
string myns = "urn:www.example.org";
ns.Add( "", myns);
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// override the (implicit) XmlRoot attribute
XmlRootAttribute attr1 = new XmlRootAttribute
{
Namespace = myns,
ElementName = "DTO-Annotations",
};
attrs.XmlRoot = attr1;
overrides.Add(typeof(DTO), attrs);
// "un-ignore" the first property
// define an XmlElement attribute, for a type of "String", with no namespace
var a2 = new XmlElementAttribute(typeof(String)) { ElementName="note", Namespace = myns };
// add that XmlElement attribute to the 2nd bunch of attributes
attrs = new XmlAttributes();
attrs.XmlElements.Add(a2);
attrs.XmlIgnore = false;
// add that bunch of attributes to the container for the type, and
// specifically apply that bunch to the "additionalInformation" property
// on the type.
overrides.Add(typeof(DTO), "additionalInformation", attrs);
// now, XmlIgnore all the other properties
attrs = new XmlAttributes();
attrs.XmlIgnore = true;
overrides.Add(typeof(DTO), "stamp", attrs);
overrides.Add(typeof(DTO), "name", attrs);
overrides.Add(typeof(DTO), "value", attrs);
overrides.Add(typeof(DTO), "index", attrs);
// create a serializer using those xml attribute overrides
XmlSerializer s2 = new XmlSerializer(typeof(DTO), overrides);
Console.WriteLine("\nSerialize using the override attributes: ");
builder.Length = 0;
using ( XmlWriter writer = XmlWriter.Create(builder, settings))
{
s2.Serialize(writer, dto, ns);
}
Console.WriteLine("{0}",builder.ToString());
Console.WriteLine("\n");
// ---------------------------------------------------------------
}
}
output, using the in-line attributes:
<DTO>
<stamp>2009-06-30T02:17:35.918Z</stamp>
<name>Marley</name>
<value>72.34</value>
<index>7</index>
</DTO>
output, using the override attributes:
<DTO-Annotations xmlns="urn:www.example.org">
<note>This will bbe serialized separately</note>
</DTO-Annotations>