Reputation: 468
We use an XSD file, published by Agresso to generate our XML files.
I have generated and XSD class, using xsd.exe, and can successfully generate XML files as per customers requests.
The namespaces area looks like
<ABWInvoice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:agrlib="http://services.agresso.com/schema/ABWSchemaLib/2011/11/14" xmlns="http://services.agresso.com/schema/ABWInvoice/2011/11/14">
And I achieve it by the following code:
public static string XmlNamespace<T>(T entity) where T: class
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true; //removing the encoding, e.g. instead of <?xml version="1.0" encoding="utf-16"?> should be <?xml version="1.0"?>
using (StringWriter sw = new StringWriter())
using (XmlWriter writer = XmlWriter.Create(sw, settings))
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("agrlib", "http://services.agresso.com/schema/ABWSchemaLib/2011/11/14");
ns.Add("xsi","http://www.w3.org/2001/XMLSchema-instance");
XmlSerializer xser = new XmlSerializer(typeof(T));
xser.Serialize(writer, entity, ns);
return sw.ToString();
}
}
We have now a customer, requiring and additional prefix to be added: "xsi:schemaLocation",so it will be
<ABWInvoice xsi:schemaLocation="http://services.agresso.com/schema/ABWInvoice/2011/11/14" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:agrlib="http://services.agresso.com/schema/ABWSchemaLib/2011/11/14" xmlns="http://services.agresso.com/schema/ABWInvoice/2011/11/14">
I have found many examples on the web, but they all add xmlns:schemaLocation and not xsi:schemaLocation. Also I cannot modify xsd class, as it will affect other customers.
As I am new to C# can one advise how to address such a request, please?
Upvotes: 1
Views: 1133
Reputation: 1062530
AFAIK, the only way to do that in code would be to add something like:
public class YourRootType
{
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Bar {
get => "http://services.agresso.com/schema/ABWInvoice/2011/11/14";
set { }
}
}
but this impacts all instances. An alternative might be to add the value via something like XSLT, but that is ugly. If you're happy to leave it in code, you could use conditional serialization, i.e. only output it when set; for example:
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Bar { get; set; }
// this pattern is recognized by the serializer itself
public bool ShouldSerializeBar() => !string.IsNullOrWhiteSpace(Bar);
and set Bar
to "http://services.agresso.com/schema/ABWInvoice/2011/11/14"
at runtime for those clients.
Another option would be to use [XmlAnyAttribute]
:
[XmlAnyAttribute]
XmlAttribute[] AdditionalAttributes { get; set; }
and attach arbitrary additional attributes at runtime. That is a bit more complex, though, because it is a bit awkward to get hold of an XmlAttribute
instance through C# - you need to create a DOM etc.
I forgot to say; in terms of making it xsi:schemaLocation
: that's where XmlSerializerNamespaces
comes in:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
ns.Add("agrlib", "http://services.agresso.com/schema/ABWSchemaLib/2011/11/14");
// etc
and pass ns
in as the last argument on XmlSerializer.Serialize
.
Upvotes: 1