XML add both a named and a default namespace error - c#

I want to create an XML file with two namespaces for my root element, one default and one named. Following is my code:
var testdoc= new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Document",
new XAttribute("xmlns", "namespace1"),
new XAttribute(XNamespace.Xmlns + "xsi", "namespace2"),
new XElement("sampleElem", "content")
)
);
This generates the following error:
the prefix for "namespace2" can not be redefined within the same code for starting a new element.
I understand the error, but I do not understand why I get it (as the prefix name is not the same). Anyone know the correct way to get the desired result?

Because in this line new XElement("Document", you have already created an element with a namespace by default. Specifying the attribute you are trying to override it.
Do this
XNamespace ns = "namespace1";
var testdoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement(ns + "Document",
new XAttribute(XNamespace.Xmlns + "xsi", "namespace2"),
new XElement("sampleElem", "content")
)
);

Related

C# Linq XDoc - add element with same name

I'm attempting to write a small XML file using c# Linq XDocument.
The final xml file should look like this:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Asset InternalID="SOMEID" LastSaveDate="2016-10-28" LastSaveTime="01:01:33:00" AssetType="New">
<type_metadata>
<FIELD name="filename">SOMEID.MOV</FIELD>
<FIELD name="duration">00:00:00:10</FIELD>
</type_metadata>
</Asset>
</Root>
Here is my code:
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));
doc.Add(new XElement("Root"));
doc.Element("Root").Add(new XElement("Asset"));
doc.Element("Root").Element("Asset").Add(new XAttribute("InternalID", a.InternalID));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveDate", a.lastSaveDate));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveTime", a.lastSaveTime));
doc.Element("Root").Element("Asset").Add(new XAttribute("AssetType", a.AssetType));
doc.Element("Root").Element("Asset").Add(new XElement("type_metadata"));
doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name","filename"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = a.filename;
doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name", "duration"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = a.duration;
Everything works fine until I try to put in the second "FIELD" element.
What is the proper way to do this? I have done some research, but I cant find a simple answer that is directly relevant to what I'm trying to accomplish.
That's because when you're trying to add second element you're using:
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD")
It will return first element matching the name, which is this case is the previously added "FIELD" element, which already has "name" attribute.
I'd suggest you create the element itself before attaching it to the document. This way you won't have to search for the element over and over again:
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));
var root = new XElement("Root");
var asset = new XElement("Asset");
asset.Add(new XAttribute("InternalID", a.InternalID));
asset.Add(new XAttribute("LastSaveDate", a.lastSaveDate));
asset.Add(new XAttribute("LastSaveTime", a.lastSaveTime));
asset.Add(new XAttribute("AssetType", a.AssetType));
var type_metadata = new XElement("type_metadata");
var field = new XElement("FIELD");
field.Add(new XAttribute("name","filename"));
field.Value = a.filename;
type_metadata.Add(field);
var field2 = new XElement("FIELD");
field2.Add(new XAttribute("name","duration"));
field2.Value = a.duration;
type_metadata.Add(field2);
asset.Add(type_metadata);
root.Add(asset);
doc.Add(root);
Also, you can create the entire document in a single statement:
XDocument doc = new XDocument(
new XDeclaration("1.0", "UTF-8", null),
new XElement("Root",
new XElement("Asset",
new XAttribute("InternalID", a.InternalID),
new XAttribute("LastSaveDate", a.lastSaveDate),
new XAttribute("LastSaveTime", a.lastSaveTime),
new XAttribute("AssetType", a.AssetType),
new Element("type_metadata",
new XElement("FIELD",
new XAttribute("name", "filename"),
a.filename),
new XElement("FIELD",
new XAttribute("name", "duration"),
a.duration)))));
It would be easier if you prepare new FIELD element before adding it to the parent element :
var filename = new XElement("FIELD",
new XAttribute("name","filename"),
a.filename
);
var duration = new XElement("FIELD",
new XAttribute("name","duration"),
a.duration
);
doc.Element("Root").Element("Asset").Element("type_metadata").Add(field);
doc.Element("Root").Element("Asset").Element("type_metadata").Add(duration);
This can be achieved in different ways. I just followed your approach. Since you have multiple FIELD elements, slight modification required in your code. The following code will work as expected.
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));
doc.Add(new XElement("Root"));
doc.Element("Root").Add(new XElement("Asset"));
doc.Element("Root").Element("Asset").Add(new XAttribute("InternalID", "intID"));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveDate", "28.10.2016"));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveTime", "1.48PM"));
doc.Element("Root").Element("Asset").Add(new XAttribute("AssetType", "Laptop"));
doc.Element("Root").Element("Asset").Add(new XElement("type_metadata"));
doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name", "filename"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = "a.txr";
doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Elements().Last().Add(new XAttribute("name", "duration"));
doc.Element("Root").Element("Asset").Element("type_metadata").Elements().Last().Value = "00:12:98";

Using XDocument and XElement how do I add a XAttribute and a value to XML in C#

I am trying to replicate:
<gcf>
<cbxDecOnly Type="Boolean">False</cbxDecOnly>
<cbxFormName Type="String" />
<txtCustomerCellPhonePart2 Type="String">5236</txtCustomerCellPhonePart2>
<txtCustomerCellPhonePart1 Type="String">533</txtCustomerCellPhonePart1>
....
</gcf>
so far I have:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("gcf",
new XElement("cbxDecOnly", new XAttribute("Type", "Boolean")),
new XElement("cbxFormName", oGSFE.TextBoxClientName),
new XElement("txtCustomerCellPhonePart2", oGSFE.TextBoxDealSearch),
new XElement("txtCustomerCellPhonePart1 ", oGSFE.DropDownListFIManager)
)
);
what I don't know is how to add a XAttribute and a value at the same time to the XML element <cbxDecOnly Type="Boolean">False</cbxDecOnly>
In the same way you provide the value for your txtCustomerCellPhonePart2 etc nodes - by including the string value as one of the element's params content[]:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("gcf",
new XElement("cbxDecOnly", "False", new XAttribute("Type", "Boolean")),
new XElement("cbxFormName", oGSFE.TextBoxClientName),
new XElement("txtCustomerCellPhonePart2", oGSFE.TextBoxDealSearch),
new XElement("txtCustomerCellPhonePart1", oGSFE.DropDownListFIManager)
)
);
Any values of type string provided in content[] will be merged into the element's value, any values of type XAttribute will create attributes and any values of type XElement will become the children.

Cannot add "xmlns" attribute to urlset in sitemap.xml

I generate a sitemap.xml
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", ""),
new XElement("urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"),
new Element (....and so on...)
I get an error
The prefix '' cannot be redefined from '' to 'http://www.sitemaps.org/schemas/sitemap/0.9' within the same start element tag.
Google requires xmlns attribute without any prefix.
Seems that adding default namespace in XDocument is a bit tricky, related question : How to set the default XML namespace for an XDocument
You can try to declare default namespace prefix and use that prefix for all elements within <urlset> like so :
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", ""),
new XElement(ns+"urlset",
new XElement(ns+"otherElement"),
new XElement (....and so on...)
You can solve this problem by using blank namespace like the following:
XNamespace blank = XNamespace.Get(#"http://www.sitemaps.org/schemas/sitemap/0.9");
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement(blank + "urlset",
new XAttribute("xmlns", blank.NamespaceName),
new XElement(blank + "loc", "http://www.abc.eba/"),
new Element (....and so on...)
));

How to wrtie a XML License Line(ended with a forward slash '/') in C#?

I want to write a XML file as below:
<?xml version="1.0" encoding="UTF-8"?>
<books xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<License licenseId="" licensePath="" />
Some piece of my code attached here
// Create a new file in D:\\ and set the encoding to UTF-8
XmlTextWriter textWriter = new XmlTextWriter("D:\\books.xml", System.Text.Encoding.UTF8);
// Format automatically
textWriter.Formatting = Formatting.Indented;
// Opens the document
textWriter.WriteStartDocument();
// Write the namespace declaration.
textWriter.WriteStartElement("books", null);
// Write the genre attribute.
textWriter.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
textWriter.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
And now I need to write the License Line below in C#
<License licenseId="" licensePath="" />
But I don't know how to move on for I found the Line ended with the forward slash / .Thank you.
I have 2 questions about the way you're doing this:
1) Do you have to use a text writer? If you have access to c# 3.0 then you can use the following:
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XAttribute(XNamespace.Xmlns + "xsd", "http://www.w3.org/2001/XMLSchema"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XElement("Equipment",
new XElement("License",
new XAttribute("licenseId", ""),
new XAttribute("licensePath", "")
)
)
);
2) Do you have to declare the two namespaces? It seems to me like you won't use them:
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Equipment",
new XElement("License",
new XAttribute("licenseId", ""),
new XAttribute("licensePath", "")
)
)
);
If you're intending to write multiple License elements to the document, and you have them in an Array, List or some other IEnumerable, you can use something similar to the code below to spit them all out:
IEnumerable<LicenceObjects> licenses = //some code to make them;
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Equipment",
licenses.Select(l =>
new XElement("License",
new XAttribute("licenseId", l.licenseId),
new XAttribute("licensePath", l.licensePath)
)
)
)
);
string xmlDocumentString = doc.ToString();
Of course, if you don't have .NET 3.0, then this is useless to you :(
Calling the WriteEndElement method will automatically take care of adding the forwards slash.
Why don't you just proceed as you started?
textWriter.WriteStartElement("Licence");
textWriter.WriteAttributeString("LicenseId", "");
textWriter.WriteAttributeString("LicensePath", "");
// Other stuff
textWriter.WriteEndDocument();
textWriter.Close();

how to add(or ignore) XML namespace when using XElement.Load

I am creating XML using Linq to XML and C#. It all works great except when I need to manually add in a row in the XML. This row is only added if I have a value to pass through to it, otherwise I just ignore the entire tag.
I use XElement.Load to load in the string of text that I store in a string but when I attach it to the XML it always puts in xmlns="" at the end of my tag.
Is there a way I can tell XElement.Load to use the existing namespace or to ignore it when putting in the string to the XML?
Ideally I just want my string to be included to the XML being created without extra tags being added.
Below is a sample of what I currently do:
string XMLDetails = null;
if (ValuePassedThrough != null)
XMLDetails = "<MyNewTag Code=\"14\" Value=\"" + ValuePassedThrough +"\"></MyNewTag>";
When I build up the XML I load the above string into my XML. It is here where xmlns="" is being added to the XMLDetails value but ideally I want this ignored as it is causing issues with the recipient when they try to read this tag.
XNamespace ns = "http://namespace-address";
XNamespace xsi = "http://XMLSchema-instance-address";
XDocument RequestDoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(ns + "HeaderTag",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(xsi + "schemaLocation", "http://www.addressofschema.xsd"),
new XAttribute("Version", "1"),
new XElement(ns + "OpeningTAG",
...My XML Code ...
XElement.Load(new StringReader(XMLDetails))
...End of XML Code ...
As mentioned above. My code works, it successfully outputs XML for me. Its just the MyNewTag tag I load in using XElement.Load gets xmlns="" added to the end of it which is causing me an issue.
Any ideas how I can work around this? Thanks for your help.
Regards,
Rich
How about:
XElement withoutNamespace = XElement.Load(new StringReader(XMLDetails));
XElement withNamespace = new XElement(ns + withoutNamespace.Name.LocalName,
withoutNamespace.Nodes());
As a better alternative - why don't you either include the namespace when you're building up the XML, or even better, create an XElement instead of manually generating an XML string which you then read. Manually creating XML is very rarely a good idea. Aside from anything else, you're assuming that ValuePassedThrough has already been escaped, or doesn't need escaping etc. That may be valid - but it's at least a cause for concern.
Like this
XElement XMLDetails = new XElement(ns + "OpeningTAG", new XElement(ns + "MyNewTag", new XAttribute("Code", 14), new XAttribute("Value", 123)));
XDocument RequestDoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(ns + "HeaderTag",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(xsi + "schemaLocation", "http://www.addressofschema.xsd"),
new XAttribute("Version", "1"),
XMLDetails));

Categories