Error parsing xml syntax error - c#

I have the following code below. I am getting an error "the character ':' hexadecimal value 0x3A cannot be included in a name" Can anyone tell me how to fix this?
Thanks Below is the entire code
public static XDocument GenerateXMLSpreadSheet(DataTable tbl)
{
new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessing**Instruction("mso-application", "Excel.Sheet"),
new XElement("Workbook",
new XAttribute("xmlns", "urn:schemas-microsoft-com:office:spreadsheet"),
new XAttribute("xmlns:ss", "urn:schemas-microsoft-
com:office:spreadsheet"),
new XElement("Worksheet", new XAttribute("ss:Name",
tbl.TableName),
new XElement("Table", GetRows(tbl)
)
)
)
);
return xmlssDoc;
)
public static Object[] GetRows(DataTable tbl)
{
// generate XElement rows for each row in the database.
// generate from the bottom-up.
// start with the cells.
XElement[] rows = new XElement[tbl.Rows.Count];
int r = 0;
foreach (DataRow row in tbl.Rows)
{
// create the array of cells to add to the row:
XElement[] cells = new XElement[tbl.Columns.Count];
int c = 0;
foreach (DataColumn col in tbl.Columns)
{
cells[c++] =
new XElement("Cell",
new XElement("Data", new XAttribute("ss:Type", "String"),
new XText(row[col].ToString())));
}
rows[r++] = new XElement("Row", cells);
}
// return the array of rows.
return rows;
}

Basically, that's not how you handle namespaces in LINQ to XML. You never specify a string with a colon in - instead, you build up an XName from an XNamespace and a string.
The good news is that LINQ to XML handling of namespaces is simple. Here's a complete example:
using System;
using System.Xml.Linq;
public class Test
{
static void Main(string[] args)
{
XNamespace ns = "urn:schemas-microsoft-com:office:spreadsheet";
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessingInstruction("mso-application", "Excel.Sheet"),
new XElement(ns + "Workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "ss", ns),
new XElement(ns + "Worksheet",
new XAttribute(ns + "Name", "my-table-name"),
new XElement(ns + "Table")
)
)
);
Console.WriteLine(doc);
}
}
Output (reformatted for clarity):
<?mso-application Excel.Sheet?>
<ss:Workbook
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<ss:Worksheet ss:Name="my-table-name">
<ss:Table />
</ss:Worksheet>
</ss:Workbook>
Note how you need to specify the namespace for all the elements and attributes.
Because you've specified an explicit prefix for the namespace, LINQ to XML uses it everywhere. If you remove this part:
new XAttribute(XNamespace.Xmlns + "ss", ns)
... then the namespace for elements will be defaulted, and LINQ to XML will generate a prefix for the attributes that need it explicitly specified (as attributes don't default their namespaces).
Then the output is (for example):
<?mso-application Excel.Sheet?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet">
<Worksheet p2:Name="my-table-name" xmlns:p2="urn:schemas-microsoft-com:office:spreadsheet">
<Table />
</Worksheet>
</Workbook>

The problem is how you defined namespaces.
To work with namespaces you may get one by calling XNamespace.Get("the namespace") and using this everywhere you want.
And for xmlns you may use static property XNamespace.Xmlns.
So the final code will look like:
new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessingInstruction("mso-application", "Excel.Sheet"),
new XElement("Workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "ss", ns),
new XElement("Worksheet", new XAttribute(ns + "Name",
tbl.TableName),
new XElement("Table", GetRows(tbl)
)
)
)
);

Related

How to add xmlns to xml document?

I'm trying to create a fairly simple XML document that looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<employees xmlns="http://website.com/xsd/MQ">
<employee>
<id>00122731</id>
<first-name>LUIS</first-name>
<last-name>GARCIA</last-name>
<subarea>4100</subarea>
<cost-center>904</cost-center>
<email-address>L.GARCIA#EMAIL.COM</email-address>
</employee>
</employees>
I was able to get the basics by using this code but I need to add the xmlns attribute and I'm not figuring out how to do that.
var xmlDoc = new XElement("employees",
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress)));
This is my attempt to add it but I get an error that this would cause and invalid structure.
XDocument xmlDoc = new XDocument(
new XElement("employees",
new XAttribute("xmlns", "http://website/xsd/MQ")),
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress))
);
UPDATE
Based on the link provided below this is what I came up with that worked.
XNamespace ns = "http://website/xsd/MQ";
var xmlDoc = new XElement(ns + "employees",
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress)));
You need to include the namespace on all of your elements, not just the top one:
XNamespace ns = "http://website/xsd/MQ";
var xmlDoc = new XElement(ns + "employees",
from e in listEmployees
select new XElement(ns + "employee",
new XElement(ns + "id", e.EmployeeId),
new XElement(ns + "first-name", e.FirstName),
new XElement(ns + "last-name", e.LastName),
new XElement(ns + "subarea", e.SubArea),
new XElement(ns + "cost-center", e.CostCenter),
new XElement(ns + "email-address", e.EmailAddress)
)
);
If that's too repetitive for you, you could make a convenience method:
XNamespace ns = "http://website/xsd/MQ";
private static XElement MQElement(string name, object contents)
{
return new XElement(ns + name, contents);
}
then use it:
var xmlDoc = MQElement("employees",
from e in listEmployees
select MQElement("employee",
MQElement("id", e.EmployeeId),
MQElement("first-name", e.FirstName),
MQElement("last-name", e.LastName),
MQElement("subarea", e.SubArea),
MQElement("cost-center", e.CostCenter),
MQElement("email-address", e.EmailAddress)
)
);
One more option to achieve same result is to construct XElement ignoring namespaces completely and then add them in separate code:
foreach (XElement e in xmlDoc.DescendantsAndSelf())
{
if (e.Name.Namespace == "")
{
e.Name = ns + e.Name.LocalName;
}
}

How do I build an xml section and save to file (not a valid xml document per se)

I´m trying to build a fraction of an XML document, to be included in a final document.
When using XDocument, I get an exception:
"This operation would create an incorrectly structured document."
because my fragment has multiple "root" nodes.
As the file is to be included in a larger document, my base elements will not end up in the root of the final document.
XDocument constsDocument = new XDocument(
new XComment($" Consts section generated on {DateTime.Now} "),
new XComment($" First group of constants. "),
FirstTextConsts(MyFirstCollection),
new XComment($" Refrigerant constants. "),
SecondTextConsts(MySecondCollection)
);
// To avoid xml file starting with <?xml version="1.0" encoding="utf-8"?> use stringbuilder and StreamWriter.
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true
};
using (XmlWriter xw = XmlWriter.Create(sb, xws))
{
constsDocument.Save(xw);
}
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputFileName);
file.WriteLine(sb.ToString());
file.Close();
EDIT 1:
The two methods called within the creation of the document (in principal):
private static IEnumerable<XElement> FirstTextConsts(IEnumerable<MyClass> collection)
{
return collection.Select(r => new XElement("const",
new XAttribute("name", $"IDENTIFIER_{r.Id}"),
new XAttribute("translatable", "false"),
new XElement("text",
new XAttribute("lang","en"), r.Name)));
}
private static IEnumerable<XElement> SecondTextConsts(IEnumerable<MyClass> collection)
{
foreach (var obj in collection)
{
if (obj.SomeSelector)
yield return new XElement("const",
new XAttribute("name", $"IDENTIFIER_{r.Id}"),
new XAttribute("translatable", "false"),
new XElement("text",
new XAttribute("lang","en"), r.Name)));
if (obj.SomeOtherSelector)
yield return new XElement("const",
new XAttribute("name", $"IDENTIFIER_{r.Id}"),
new XAttribute("translatable", "true")
);
}
}
EDIT 2:
As I really need the flexibility of XDocument to build a multilevel xml document wit helper methods returning IEnumerable on different levels, I decided to add a phony element and remove it again before writing to file:
XDocument constsDocument = new XDocument(
new XElement("root",
new XComment($" Consts section generated on {DateTime.Now} "),
new XComment($" First group of constants. "),
FirstTextConsts(MyFirstCollection),
new XComment($" Refrigerant constants. "),
SecondTextConsts(MySecondCollection)
)
);
Before writing to file i strip the element:
file.WriteLine(sb.ToString().Replace("<root>" + Environment.NewLine, "").Replace(Environment.NewLine + "</root>", ""));
You can't create an XDocument that is invalid (due to the multiple "root" nodes). You therefore need to create a list of nodes, and write those to the document fragment.
var constsDocument = new List<XNode> {
new XComment($" Consts section generated on {DateTime.Now} "),
new XComment($" First group of constants. "),
new XElement("example"),
new XComment($" Refrigerant constants. "),
new XElement("another")
};
// To avoid xml file starting with <?xml version="1.0" encoding="utf-8"?> use stringbuilder and StreamWriter.
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true,
ConformanceLevel = ConformanceLevel.Fragment
};
using (XmlWriter xw = XmlWriter.Create(sb, xws))
{
foreach (var element in constsDocument)
{
element.WriteTo(xw);
}
}
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputPath);
file.WriteLine(sb.ToString());
file.Close();
EDIT: to use a method which returns an IEnumerable<XElement> inside the object initializer for the List, you would have to change the definition slightly and the way you add the other items:
var constsDocument = new List<IEnumerable<XNode>> {
new [] { new XComment($" Consts section generated on {DateTime.Now} ") },
new [] { new XComment($" First group of constants. ") },
FirstTextConsts(MyFirstCollection),
new [] { new XComment($" Refrigerant constants. ") },
SecondTextConsts(MySecondCollection)
);
...
foreach (var element in constsDocument.SelectMany(n => n))
You could declare that you want XML to be just a fragment and switch from XDocument to XMLDocument:
XmlDocument constDocument = new XmlDocument();
constDocument.CreateComment(" Consts section generated on {DateTime.Now} ");
constDocument.CreateComment(" First group of constants. ");
FirstTextConsts(MyFirstCollection); // Need to be adapted
constDocument.CreateComment(" Refrigerant constants. ");
SecondTextConsts(MySecondCollection); // Need to be adapted
XmlDocumentFragment fragDocument = constDocument.CreateDocumentFragment();
fragDocument.InnerXml = "<const>fragment</const><const>fragment2</const>"; // Need to be adapted
StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Fragment,
OmitXmlDeclaration = true,
Indent = true
};
using (XmlWriter xw = XmlWriter.Create(sb, xws))
{
fragDocument.WriteContentTo(xw);
}
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputFileName);
file.WriteLine(sb.ToString());
file.Close();
or add aritificial root element:
"<aritificialroot>" + fragment + "</aritificialroot>"

C# with XDocument and xsi:schemaLocation

I want to create the following XML.
<?xml version="1.0" encoding="utf-8"?>
<MyNode xsi:schemaLocation="https://MyScheme.com/v1-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://MyScheme.com/v1-0 Sscheme.xsd">
<MyInfo>
<MyNumber>string1</MyNumber>
<MyName>string2</MyName>
<MyAddress>string3</MyAddress>
</MyInfo>
<MyInfo2>
<FirstName>string4</FirstName>
</MyInfo2>
</MyNode>
I'm using this code.
XNamespace xmlns = "https://MyScheme.com/v1-0 Sscheme.xsd";
XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
XNamespace schemaLocation = XNamespace.Get("https://MyScheme.com/v1-0");
XDocument xmlDocument = new XDocument(
new XElement(xmlns + "MyNode",
new XAttribute(xsi + "schemaLocation", schemaLocation),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement("MyInfo",
new XElement("MyNumber", "string1"),
new XElement("MyName", "string2"),
new XElement("MyAddress", "string3")
),
new XElement("MyInfo2",
new XElement("FirstName", "string4")
)
)
);
xmlDocument.Save("C:\\MyXml.xml");
However, I'm getting xmlns="" inside tags MyInfo and MyInfo2.
Can somebody help me to create the correct XML?
You need to use xmlns XNamespace for all elements, because that is default namespace and it is declared at root level element. Note that descendant elements inherit ancestor default namespace implicitly, unless otherwise specified :
XDocument xmlDocument = new XDocument(
new XElement(xmlns + "MyNode",
new XAttribute(xsi + "schemaLocation", schemaLocation),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement(xmlns+"MyInfo",
new XElement(xmlns+"MyNumber", "string1"),
new XElement(xmlns+"MyName", "string2"),
new XElement(xmlns+"MyAddress", "string3")
),
new XElement(xmlns+"MyInfo2",
new XElement(xmlns+"FirstName", "string4")
)
)
);
Dotnetfiddle Demo

How to create XML in C#

I need to create an XML and return it as a string. Can anyone tell me how to create the following XML using XmlDocument?
<outputs>
<output name="" value="" type=""></output>
<output name="" value="" type=""></output>
<output name="" value="" type=""></output>
</outputs>
UPDATE
var xmlDocument = new XmlDocument();
var xmlNode=xmlDocument.CreateNode(XmlNodeType.XmlDeclaration,"outputs","namespace");
xmlDocument.AppendChild(xmlNode);
var xmlElement = xmlDocument.CreateElement("", "output", "");
xmlDocument.AppendChild(xmlElement);
I think you should consider using XDocument instead of XmlDocument:
var doc = new XDocument(new XElement("outputs",
new XElement("output",
new XAttribute("name", ""),
new XAttribute("value", ""),
new XAttribute("type", "")),
new XElement("output",
new XAttribute("name", ""),
new XAttribute("value", ""),
new XAttribute("type", "")),
new XElement("output",
new XAttribute("name", ""),
new XAttribute("value", ""),
new XAttribute("type", ""))));
You can than easily write the xml into a string:
var myXmlString = doc.ToString();
You can also achieve the same goal with XDocument.Parse() static method:
var doc = XDocument.Parse("<outputs><output></output> (...) </outputs>");
You can add content using loop as well:
var doc = new XDocument(new XElement("outputs"));
var root = doc.Root;
foreach(var o in outputs)
{
root.Add(new XElement("output",
new XAttribute("name", o.Name),
new XAttribute("value", o.Value),
new XAttribute("type", o.Type)));
}
//Create XmlDocument
XmlDocument xmlDoc = new XmlDocument();
//Create the root element
XmlNode outputsElement = xmlDoc.CreateElement("outputs");
//Create the child element
XmlElement Element = xmlDoc.CreateElement("output");
//Create "name" Attribute
XmlAttribute nameAtt = xmlDoc.CreateAttribute("name");
Element.Attributes.Append(nameAtt);
//Create "value" Attribute
XmlAttribute valueAtt = xmlDoc.CreateAttribute("value");
Element.Attributes.Append(valueAtt);
//Create "type" Attribute
XmlAttribute typeAtt = xmlDoc.CreateAttribute("type");
Element.Attributes.Append(typeAtt);
//Append child element into root element
outputsElement.AppendChild(Element);
and to return it as string:
xmlDoc.OuterXml;
string str = "<outputs><output name=\"\" value=\"\" type=\"\"></output><output name=\"\" value=\"\" type=\"\"></output><output name=\"\" value=\"\" type=\"\"></output></outputs>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(str);
And for creating a string again.
string toString = string.Empty;
using (StringWriter stringWriter = new StringWriter())
{
XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
doc.WriteTo(xmlTextWriter);
toString = stringWriter.ToString();
}
This will help you a lot, it is a great example about how to Read and Write to an xml file:
http://www.c-sharpcorner.com/UploadFile/mahesh/ReadWriteXMLTutMellli2111282005041517AM/ReadWriteXMLTutMellli21.aspx
Example code about how to Create elements and a whole XML file, using c# code:
static void Main(string[] args)
{
// Create a new file in C:\\ dir
XmlTextWriter textWriter = new XmlTextWriter("C:\\myXmFile.xml", null);
// Opens the document
textWriter.WriteStartDocument();
// Write comments
textWriter.WriteComment("First Comment XmlTextWriter Sample Example");
textWriter.WriteComment("myXmlFile.xml in root dir");
// Write first element
textWriter.WriteStartElement("Student");
textWriter.WriteStartElement("r", "RECORD", "urn:record");
// Write next element
textWriter.WriteStartElement("Name", "");
textWriter.WriteString("Student");
textWriter.WriteEndElement();
// Write one more element
textWriter.WriteStartElement("Address", ""); textWriter.WriteString("Colony");
textWriter.WriteEndElement();
// WriteChars
char[] ch = new char[3];
ch[0] = 'a';
ch[1] = 'r';
ch[2] = 'c';
textWriter.WriteStartElement("Char");
textWriter.WriteChars(ch, 0, ch.Length);
textWriter.WriteEndElement();
// Ends the document.
textWriter.WriteEndDocument();
// close writer
textWriter.Close();
}

How to create an Xml with multiple namescapes using XDocument

I would like to create a document with multiple namespaces (see Xml below). How can I do that using XDocument? My final result should the following:
<?xml version="1.0" encoding="utf-8"?>
<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://schemas.zune.net/catalog/apps/2008/02">
<a:link rel="prev" type="application/atom+xml" href="myUrl" />
<a:link rel="next" type="application/atom+xml" href="myUrl" />
<a:link rel="self" type="application/atom+xml" href="myUrl" />
<a:updated>2008-05-20T22:50:46.7932864Z</a:updated>
Here is the code I have so far.
XNamespace nsW3Atom = "http://www.w3.org/2005/Atom";
XNamespace nsOs = "http://a9.com/-/spec/opensearch/1.1/";
XNamespace nsZune = "http://schemas.zune.net/calatog/apps/2008/02";
XDocument doc =
new XDocument(
// new XDeclaration("1.0", "utf-8", "no"),
new XElement("feed",
new XAttribute("a", nsW3Atom),
new XAttribute("os", nsOs),
new XAttribute("os2", nsZune),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "prev"), new XAttribute("type", "application/atom+xml")),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "next"), new XAttribute("type", "application/atom+xml")),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "self"), new XAttribute("type", "application/atom+xml"))));
Thank you in advance for the help!
XNamespace a="http://www.w3.org/2005/Atom";
XNamespace os = "http://a9.com/-/spec/opensearch/1.1/";
XNamespace def = "http://schemas.zune.net/catalog/apps/2008/02";
var doc =
new XDocument(new XElement(a + "feed",
new XAttribute(XNamespace.Xmlns + "a", a),
new XAttribute(XNamespace.Xmlns + "os", os),
new XAttribute("xmlns", def)));
then if You want to use the a Namespace, prefix any element with a+
When creating the attributes use the xmlns: prefix.
new XAttribute("xmlns:a", nsW3Atom),
new XAttribute("xmlns:os", nsOs),
new XAttribute("xmlns:os2", nsZune)

Categories