How do I add a namespace when creating an XML file? - c#

I have to create an XML document in C#.
The root element has to look like this:
<valuation-request
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="valuations.xsd">
I'm using the following
XmlElement root = X.CreateElement("valuation-request");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
root.SetAttribute("xsi:noNamespaceSchemaLocation", "valuations.xsd");
However this produces
<valuation-request
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
noNamespaceSchemaLocation="valuations.xsd"> //missing the xsi:
What am I missing?

Use the overload of SetAttribute, that takes namespace as well:
root.SetAttribute("noNamespaceSchemaLocation",
"http://www.w3.org/2001/XMLSchema-instance",
"valuations.xsd"
);

With writer you add it like this:
var writerSettings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
Encoding = new UTF8Encoding(false)
};
XmlWriter writer = XmlWriter.Create("C:\test.xml", writerSettings);
writer.WriteStartDocument(false);
writer.WriteStartElement("valuation-request");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xsi", "noNamespaceSchemaLocation", null, "http://www.gzs.si/e-poslovanje/sheme/eSLOG_1-5_EnostavniRacun.xsd");

Recently, I have encountered same issue. To resolve it, I've just add the follow line:
XmlAttribute noNamespaceSchemaLocationAttr = xmlDoc.CreateAttribute("xsi", "noNamespaceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance");

Related

Missing xml header when convert json to xml in C# [duplicate]

Consider the following simple code which creates an XML document and displays it.
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement("root");
xml.AppendChild(root);
XmlComment comment = xml.CreateComment("Comment");
root.AppendChild(comment);
textBox1.Text = xml.OuterXml;
it displays, as expected:
<root><!--Comment--></root>
It doesn't, however, display the
<?xml version="1.0" encoding="UTF-8"?>
So how can I get that as well?
Create an XML-declaration using XmlDocument.CreateXmlDeclaration Method:
XmlNode docNode = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
xml.AppendChild(docNode);
Note: please take a look at the documentation for the method, especially for encoding parameter: there are special requirements for values of this parameter.
You need to use an XmlWriter (which writes the XML declaration by default). You should note that that C# strings are UTF-16 and your XML declaration says that the document is UTF-8 encoded. That discrepancy can cause problems. Here's an example, writing to a file that gives the result you expect:
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement("root");
xml.AppendChild(root);
XmlComment comment = xml.CreateComment("Comment");
root.AppendChild(comment);
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
ConformanceLevel = ConformanceLevel.Document,
OmitXmlDeclaration = false,
CloseOutput = true,
Indent = true,
IndentChars = " ",
NewLineHandling = NewLineHandling.Replace
};
using ( StreamWriter sw = File.CreateText("output.xml") )
using ( XmlWriter writer = XmlWriter.Create(sw,settings))
{
xml.WriteContentTo(writer);
writer.Close() ;
}
string document = File.ReadAllText( "output.xml") ;
XmlDeclaration xmldecl;
xmldecl = xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = xmlDocument.DocumentElement;
xmlDocument.InsertBefore(xmldecl, root);

How to serialise with custom namespace

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";
}

XAttribute generates bogus prefix

I am trying to generate a piece of xml data using linq to xml.
XNamespace xsins = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
XAttribute xsiniltrue = new XAttribute(xsins+"Exists", "true");
XElement elem = new XElement("CustomerRecord", xsiniltrue);
This generates the prefix for xsins at runtime and they looks bogus.
<Fragment>
<CustomerRecord p5:Exists="true" xmlns:p5="w3.org/2001/XMLSchema-instance"; />
</Fragment>
<Fragment>
<CustomerRecord p3:Exists="false" xmlns:p3="w3.org/2001/XMLSchema-instance"; />
</Fragment>
to be merged as
<Fragment xmlns:p5="w3.org/2001/XMLSchema-instance"; >
<CustomerRecord p5:Exists="true" />
<CustomerRecord p5:Exists="false" />
</Fragment>
Also tried to use XMLWriter,
XNamespace xsins = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
using (var writer = XmlWriter.Create(fullPath, settings))
{
writer.WriteStartDocument(true);
writer.WriteStartElement(string.Empty, "Company", "urn:schemas-company");
//writer.WriteAttributeString(xsins.GetName("xsi"), "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteStartElement(string.Empty, "Add", "urn:schemas-company");
foreach (var qx in resultXMLs)
{
qx.WriteTo(writer);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
}
I have finally cracked it (atleast I hope), below piece solved my issue
using (var writer = XmlWriter.Create(fullPath, settings))
{
writer.WriteStartDocument(true);
writer.WriteStartElement(string.Empty, "Company", "urn:schemas-company");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteStartElement(string.Empty, "Add", "urn:schemas-company");
foreach (var qx in fragments)
{
qx.SetAttributeValue(XNamespace.Xmlns + "xsi", xsins.ToString());
qx.WriteTo(writer);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
}
You want to control the XML prefix outputted. For reference an MSDN site
Basically you just need to add the xml:xsi to your root node and Linq to XML should take care of the rest.
Note that when you get into really complex examples it tends to fall apart, but it should work in this case.
EDIT:
To remove extraneous attributes, you could simply do it by hand:
foreach(var element in root.Descendents())
{
foreach (var attribute in element.Attributes())
{
if (attribute.Name.Namespace == XNamespace.Xmlns)
attribute.Remove();
}
}
Note the above is rough, I don't have an XML project handy.
EDIT:
I am not sure what your input is, but here is an example of hard coding your expected output:
var xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
var fragment =
new XElement("Fragment",
new XAttribute(XNamespace.Xmlns + "p5", xsi.ToString()),
new XElement("CustomerRecord",
new XAttribute(xsi + "Exists", "true")),
new XElement("CustomerRecord",
new XAttribute(xsi + "Exists", "false")));
I tested this and it outputs identical to what you asked for (well I tested in F#, so sorry if there is a syntax error)

XmlDocument from XML string that contains custom namespaces causes XmlException?

I need to create an XmlDocument partly by using old XML and partly by creating new. The problem is that the old XML contains custom namespaces and I can't seem to be able to use them as I get an XmlException. I've tried to add the namespace to many different places but I can't get over the Exception!
The Exception
System.Xml.XmlException was unhandled by user code
Message='my' is an undeclared prefix. Line 1, position 42.
Source=System.Xml
My Code
XmlDocument doc = new XmlDocument();
XmlSchema schema = new XmlSchema();
schema.Namespaces.Add("my", "http://foobar.com/");
doc.Schemas.Add(schema);
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(dec);
XmlElement root = doc.CreateElement("root");
root.SetAttribute("xmlns:my", "http://foobar.com/");
doc.AppendChild(root);
foreach (var item in GetItems())
{
XmlElement elem = doc.CreateElement("item");
elem.SetAttribute("id", item.id);
// Append body to elem
XmlElement body = doc.CreateElement("body");
body.InnerXml = item.Body; // Here is where I get the exception
elem.AppendChild(body);
// Append elem to root
root.AppendChild(elem);
}
Input from Item.Body is similar to
<aaa><bbb my:attr="55">Foo</bbb></aaa>
I expected the output to be similar to
<?xml version="1.0" encoding="utf-8"?>
<root my:attr="http://foobar.com/">
<item id="12345">
<body>
<aaa>
<bbb my:attr="55">Foo</bbb>
</aaa>
</body>
</item>
</root>
I'm open to alternatives to using this method. After I create the XmlDocument I prettyprint it, validate it against a schema and then push it out for the user to see.
The following is a workaround, best I can come up with:
XNamespace my = "http://foobar.com/";
var doc = new XDocument(new XElement("root",
new XAttribute(XNamespace.Xmlns + "my", my)));
var body = new XElement("body");
doc.Root.Add(new XElement("item", new XAttribute("id", 12345), body));
string innerItem = #"<aaa><bbb my:attr=""55"">Foo</bbb></aaa>";
string itemWrap = #"<wrap xmlns:my=""http://foobar.com/"">" + innerItem + "</wrap>";
XElement item = XElement.Parse(itemWrap);
body.Add(item.Element("aaa"));
Console.WriteLine(doc);

How to create in memory XML document and get string out of it

I would like to create the XML string with special characters handling. However it turned out to be too complicated and causing issues by generating wrong XML.
Now i was thinking to build the string using some object from System.xml and then stringify() or get string from it. This will i guess help me from special character cases.
//Psudo code
xmlDoc doc = new XMLDoc();
Element ele= new Element("xyz");
ele.value(Oob.property)
doc.appendNode(ele);
...
doc.getXMLString();
Can some one please let me know how to do this in C# .NET2.0+ .
I find XmlTextWriter more intuitive than XmlDocument for editing.
e.g.:
string xmlString = null;
using(StringWriter sw = new StringWriter())
{
XmlTextWriter writer = new XmlTextWriter(sw);
writer.Formatting = Formatting.Indented; // if you want it indented
writer.WriteStartDocument(); // <?xml version="1.0" encoding="utf-16"?>
writer.WriteStartElement("TAG"); //<TAG>
// <SUBTAG>value</SUBTAG>
writer.WriteStartElement("SUBTAG");
writer.WriteString("value");
writer.WriteEndElement();
// <SUBTAG attr="hello">world</SUBTAG>
writer.WriteStartElement("SUBTAG");
writer.WriteStartAttribute("attr");
writer.WriteString("hello");
writer.WriteEndAttribute();
writer.WriteString("world");
writer.WriteEndElement();
writer.WriteEndElement(); //</TAG>
writer.WriteEndDocument();
xmlString = sw.ToString();
}
after this code xmlString will contain:
<?xml version="1.0" encoding="utf-16"?>
<TAG>
<SUBTAG>value</SUBTAG>
<SUBTAG attr="hello">world</SUBTAG>
</TAG>
ADDITIONAL INFO:
using XmlDocument would be:
XmlDocument doc = new XmlDocument();
XmlNode tagNode = doc.CreateNode(XmlNodeType.Element, "TAG", null);
doc.AppendChild(tagNode);
XmlNode subTagNode1 = doc.CreateNode(XmlNodeType.Element, "SUBTAG", null);
tagNode.AppendChild(subTagNode1);
XmlText subTagNode1Value = doc.CreateTextNode("value");
subTagNode1.AppendChild(subTagNode1Value);
XmlNode subTagNode2 = doc.CreateNode(XmlNodeType.Element, "SUBTAG", null);
tagNode.AppendChild(subTagNode2);
XmlAttribute subTagNode2Attribute = doc.CreateAttribute("attr");
subTagNode2Attribute.Value = "hello";
subTagNode2.Attributes.SetNamedItem(subTagNode2Attribute);
XmlText subTagNode2Value = doc.CreateTextNode("world");
subTagNode2.AppendChild(subTagNode2Value);
string xmlString = null;
using(StringWriter wr = new StringWriter())
{
doc.Save(wr);
xmlString = wr.ToString();
}
You can also refer to this community wiki question, which leads to easier-to-read syntax when you need to build an xml stream programatically.
You can then just call the .ToString() method to get a clean escaped representation of your XML stream.
var xmlString = new XElement("Foo",
new XAttribute("Bar", "some & value with special characters <>"),
new XElement("Nested", "data")).ToString();
And you would get in xmlString:
<Foo Bar="some & value with special characters <>">
<Nested>data</Nested>
</Foo>

Categories

Resources