Reputation: 9541
How can I generate, for example, this XML in C#
<?xml version='1.0'?>
<oneshot xmlns='http://www.w3.org/2002/xforms' xmlns:dm='http://mobileforms.foo.com/xforms' xmlns:h='http://www.w3.org/1999/xhtml' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<dm:form_namespace>Foo</dm:form_namespace>
<Days>6</Days>
<Leave_Type>Option 3</Leave_Type>
</oneshot>
I'm specifically struggling with the xmlns:dm declaration. Any ideas?
Upvotes: 4
Views: 10188
Reputation: 8191
This code does the trick!
public void WriteXml(XmlWriter writer)
{
const string ns1 = "http://firstline.com/";
const string xsi = "http://www.w3.org/2001/XMLSchema-instance";
writer.WriteStartElement("myRoot", ns1);
writer.WriteAttributeString("SchemaVersion", "1.0");
writer.WriteAttributeString("xmlns", "xsi", "http://www.w3.org/2000/xmlns/", xsi);
writer.WriteAttributeString("xsi", "schemaLocation", xsi, ns1 + " schema1.xs");
writer.WriteStartElement("element1", ns1);
writer.WriteElementString("test1", ns1, "test value");
writer.WriteElementString("test2", ns1, "value 2");
writer.WriteEndElement();
writer.WriteEndElement();//to close classname that has root xml
}
Xml with multiple awesome namespaces!
<?xml version="1.0" encoding="utf-16"?>
<myClassNameWhereIXmlSerializableIsImplemented>
<myRoot SchemaVersion="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://firstline.com/ schema1.xs" xmlns="http://firstline.com/">
<element1>
<test1>test value</test1>
<test2>value 2</test2>
</element1>
</myRoot>
</myClassNameWhereIXmlSerializableIsImplemented>
There is something confusing about this line
writer.WriteAttributeString("xmlns", "xsi", "http://www.w3.org/2000/xmlns/", xsi);
if you give a random url instead of "http://www.w3.org/2000/xmlns/"
, it will fail. The url that appear in xml is actually from "xsi" variable.
One more example to prove the point
writer.WriteAttributeString("xml", "base", "http://www.w3.org/XML/1998/namespace", base1);
where base1 = "<custom url>"
and if you want to output with a prefix like this <d:test1>somevalue<\d:test1>
then writer.WriteElementString("d","test1", ns1, "somevalue");
if ns1 is not defined above then it will be added in xml output.
but for
<d:test1>
<blah>...
<\d:test1>
StartElement is needed writer.WriteStartElement("test1", ns1);
to be closed when needed with writer.WriteEndElement();
Upvotes: 0
Reputation: 9541
Thanks, all, for the help! It was a combination of two of the above answers that did it for me. I'm going to set the one that suggested the IXmlSerializable approach as that was the majority of the solution.
I had to declare the XMLRoot tag on the class name, remove WriteStartElement and WriteEndElement, and then use the four parameter declaration.
This is the class that worked in the end:
[Serializable]
[XmlRoot("oneshot")]
public class LeaveRequestPush : IXmlSerializable
{
public string FormNamespace { get; set; }
public int Days { get; set; }
public string LeaveType { get; set; }
#region IXmlSerializable
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("dm", "form_namespace", "http://mobileforms.devicemagic.com/xforms", FormNamespace);
writer.WriteElementString("Days", Days.ToString());
writer.WriteElementString("Leave_Type", LeaveType);
}
}
public void ReadXml (XmlReader reader)
{
// populate from xml blob
}
public XmlSchema GetSchema()
{
return(null);
}
Again, thanks all for the combined efforts. I would not have got this one by myself!
Upvotes: 0
Reputation: 100630
One way to write XML with nodes in different namespaces is to use 4-argument version of XmlWriter.WriteElementString to explicitly specify namespace and prefixes the way you want:
var s = new StringWriter();
using (var writer = XmlWriter.Create(s))
{
writer.WriteStartElement("oneshot", "http://www.w3.org/2002/xforms");
writer.WriteElementString("dm", "form_namespace",
"http://mobileforms.foo.com/xforms","Foo");
// pick "http://www.w3.org/2002/xforms" by default for Days node
writer.WriteElementString("Days", "6");
// or you can explicitly specify "http://www.w3.org/2002/xforms"
writer.WriteElementString("Leave_Type",
"http://www.w3.org/2002/xforms", "Option 3");
writer.WriteEndElement();
}
Console.Write(s.ToString());
Note that your sample XML defines more prefixes than are used in the XML. If your requirement is to produce "text identical XML" (vs. identical from XML point of view, but not necessary represented with identical text) you may need to put more effort in adding namespace prefixes and xmlns attributes in places you need.
Note 2: creating XML object first (XDocument for modern/LINQ way, or XmlDocument if you like DOM more) may be easier approach.
Upvotes: 1
Reputation: 18118
Try using the XAML serializer from .NET 4.0+'s assembly System.Xaml.
You may need to add attributes to mark properties as content instead of XML attributes.
Upvotes: 0
Reputation: 16934
Your best bet (read: minimal amount of hacks) is probably going to be a custom IXmlSerializable
implementation; you can get part-way to what you want via combinations of XmlRootAttribute
, XmlElementAttribute
, etc, like so:
[Serializable]
[XmlRoot("oneshot")]
public class OneShot
{
[XmlElement("form_namespace", Namespace="http://mobileforms.foo.com/xforms")]
public string FormNamespace {get; set;}
[XmlElement("Days")]
public int Days {get; set;}
[XmlElement("Leave_Type")]
public string LeaveType {get; set;}
Which will generate something like:
<?xml version="1.0" encoding="utf-16"?>
<oneshot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<form_namespace xmlns="http://mobileforms.foo.com/xforms">Foo</form_namespace>
<Days>6</Days>
<Leave_Type>Option 3</Leave_Type>
</oneshot>
But if you implement IXmlSerializable
, you have full control:
public class OneShot : IXmlSerializable
{
public string FormNamespace {get; set;}
public int Days {get; set;}
public string LeaveType {get; set;}
#region IXmlSerializable
public void WriteXml (XmlWriter writer)
{
writer.WriteStartElement("oneshot");
writer.WriteAttributeString("xmlns", null, "http://www.w3.org/2002/xforms");
writer.WriteAttributeString("xmlns:dm", null, "http://mobileforms.foo.com/xforms");
writer.WriteAttributeString("xmlns:h", null, "http://www.w3.org/1999/xhtml");
writer.WriteAttributeString("xmlns:xsd", null, "http://www.w3.org/2001/XMLSchema");
writer.WriteElementString("dm:form_namespace", null, FormNamespace);
writer.WriteElementString("Days", Days.ToString());
writer.WriteElementString("Leave_Type", LeaveType);
writer.WriteEndElement();
}
public void ReadXml (XmlReader reader)
{
// populate from xml blob
}
public XmlSchema GetSchema()
{
return(null);
}
#endregion
}
Which gives you:
<?xml version="1.0" encoding="utf-16"?>
<OneShot>
<oneshot xmlns="http://www.w3.org/2002/xforms" xmlns:dm="http://mobileforms.foo.com/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<dm:form_namespace>Foo</dm:form_namespace>
<Days>6</Days>
<Leave_Type>Option 3</Leave_Type>
</oneshot>
</OneShot>
Upvotes: 3