creating elements with namespace prefix based on multipart xml root declaration - c#

If I do something like this:
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlElement e = xmlDoc.CreateElement("ShipmentReceiptNotification");
e.SetAttribute("xmlns", "urn:rosettanet:specification:interchange:ShipmentReceiptNotification:xsd:schema:02.02");
e.SetAttribute("xmlns:ssdh", "urn:rosettanet:specification:domain:Procurement:AccountClassification:xsd:codelist:01.03");
XmlNode ShipmentReceiptNotification0Node = e;
ShipmentReceiptNotification0Node.InnerText = String.Empty;
xmlDoc.AppendChild(ShipmentReceiptNotification0Node);
XmlNode DocumentHeader1Node = xmlDoc.CreateElement("ssdh:DocumentHeader");
ShipmentReceiptNotification0Node.AppendChild(DocumentHeader1Node);
It will result in the prefix of the second node ssdh not to display, only DocumentHeader is displayed. How could I fix this?

You need to create it like this:
XmlNode DocumentHeader1Node = xmlDoc.CreateElement("ssdh", "DocumentHeader", "urn:rosettanet:specification:domain:Procurement:AccountClassification:xsd:codelist:01.03");
The point is XmlDocument needs to know which namespace prefix (first argument) corresponds which namespace URI (third argument). A little bit counter-intuitive, but this is the way it works.
Also note that the line ShipmentReceiptNotification0Node.InnerText = String.Empty; is useless; it's safe to omit it, the element is empty by default.

Related

Set XML string using node.innerXML - use of prefix causes error

I am creating a huge xml from DB and most of it's part is hard-coded(pre-defined values),so I decided to create string using StringBuilder and assigning it to node's InnerXML but prefix used for one of the attribute is not allowing me to set the string stating "Prefix not declared".
XMLNode addr = DocumentElement.createElement("element","address",null);
addr.InnerXML = "<test><s1>ttt</s1><s2 xsi:type="test">yyy</s2></test>";
prefix xsi is causing the error here. Is there any workaround for this.
xsi seems to be a namespace. You will need to either declare that namespace or not use it. Using it without declaring it is invalid.
Had some similar problem, the only way I found to fix this problem, is to add the needed namespace to your InnserXml:
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml("<Document xmlns=\"www.abc.com\" xmlns:xsi=\"w3.org/2001/XMLSchema-instance\"></Document>");
XmlNode t = xdoc.CreateElement("element", "t", null);
t.InnerXml = "<originalText xmlns:xsi=\"w3.org/2001/XMLSchema-instance\"><reference xsi:value=\"testVal\"/></originalText>";
xdoc.FirstChild.AppendChild(t);
The workaround is:
Firstly simply create XMLDocument and assign plain innerXML without namespace and prefixes as
XmlDocument ccda_xDoc = new XmlDocument();
ccda_xDoc.LoadXml("<ClinicalDocument></ClinicalDocument>");
XmlElement root = ccda_xDoc.DocumentElement;
root.InnerXml = #" My XML String without Prefix for any namespace";
Then Search for the node where you want to apply prefix to and add attribute with prefix:
XmlNode xsiValue = root.SelectSingleNode("encounter/code[#code='99201']");
XmlAttribute xsitype = structuredBody.CreateAttribute("sdtc", "valueSet", "urn:hl7-org:sdtc");
xsitype.Value = "2.16.840.1.113883.3.464.1003.101.12.1047";
xsiValue.Attributes.Prepend(xsitype);
Finally Apply namespaces to root node as :
ccda_xDoc.DocumentElement.SetAttribute("xmlns", "urn:hl7-org:v3");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:voc", "urn:hl7-org:v3/voc");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:sdtc", "urn:hl7-org:sdtc");

C# parsing Xml SelectingNode

I'm having troubles using Xml on my C# program.
the xml http://pastebin.com/Ufxaght6 (from sandbox)
I'm trying to get any info on the XML, I succeed using recursive loop on nodes, but I want to use something more efficient.
I'm trying this :
XmlDocument document = new XmlDocument();
document.LoadXml(response);
XmlNode node = document.SelectSingleNode("/getnewsalesresult/request/user");
if (node != null)
Logger.WriteLine(node.InnerText);
else
Logger.WriteLine("fail");
This gives always a null.
I think the problem comes from the 'getnewsalesresult' (Wildcard maybe ?).
From the XML :
<getnewsalesresult xmlns="http://www.sandbox.priceminister.com/res/schema/getnewsales" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sandbox.priceminister.com/res/schema/getnewsales http://www.sandbox.priceminister.com/res/schema/getnewsales/getnewsales.2014-02-11.xsd">
Any idea ?
Thanks in advance.
Your XML has default namespace (xmlns="..."). Default namespace has a different nature. The element where the default namespace declared and all of it's descendant without prefix and without different namespace declaration considered in the same default namespace.
The easiest way to get element in namespace is just to ignore the namespace (as also suggested in comment to this question) :
string xpath = "/*[local-name()='getnewsalesresult']/*[local-name()='request']/*[local-name()='user']";
XmlNode node = document.SelectSingleNode(xpath);
A more proper way is to register a prefix that mapped to the default namespace URI, then use that prefix in your XPath :
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
ns.AddNamespace("d", "http://www.sandbox.priceminister.com/res/schema/getnewsales");
XmlNode node =
document.SelectSingleNode("/d:getnewsalesresult/d:request/d:user", ns);
don't miss to pass XmlNamespaceManager object as 2nd parameter of SelectSingleNode().

How to modify DocumentElement.Prefix in XmlDocument

I have some sets of xml in which I have to add namespace prefix on nodes which doesn't have any prefix.
I have written a code which works for all nodes other than root element.
Please point me to the thing which I can do change the root element prefix as well.
private void ReplaceFile(string xmlfile)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlfile);
var a = doc.CreateAttribute("xmlns:mailxml12tm");
a.Value = "http://idealliance.org/Specs/mailxml12.0a/mailxml_tm";
doc.DocumentElement.Attributes.Append(a);
doc.DocumentElement.Prefix = "mailxml12tm";
//foreach (XmlNode item in doc.SelectNodes("//*").Cast<XmlNode>().Where(item => item.Prefix.Length == 0))
//{
// item.Prefix = "mailxml12tm";
//}
doc.Save(xmlfile);
}
The xml file:
<DeliveryApptCreateRequest
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
p3:ApptType="Pallet" p3:PickupOrDelivery="Delivery"
p3:ShipperApptRequestID="4490B0C07355" p3:SchedulerCRID="6498874"
xmlns:p3="http://idealliance.org/Specs/mailxml12.0a/mailxml_defs">
<SubmitterTrackingID xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm">2CAD3FBC71B1E1517021</SubmitterTrackingID>
<DestinationEntry xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm">No</DestinationEntry>
<OneTimeAppt xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm">
<PreferredAppt>2012-07-01T09:00:00Z</PreferredAppt>
</OneTimeAppt>
</DeliveryApptCreateRequest>
Have you seen this answer: https://stackoverflow.com/a/2255337/219344
by Jeff Sternal?
If you've already declared your namespace in the root node, you just
need to change the SetAttribute call to use the unprefixed attribute
name. So if your root node defines a namespace like this:
<People xmlns:s='http://niem.gov/niem/structures/2.0'>
You can do this and the attribute will pick up the prefix you've
already established:
// no prefix on the first argument - it will be rendered as //
s:id='ID_Person_01' TempElement.SetAttribute("id",
"http://niem.gov/niem/structures/2.0", "ID_Person_01");
If you have not yet declared the namespace (and its prefix), the
three-string XmlDocument.CreateAttribute overload will do it for you:
// Adds the declaration to your root node var attribute =
xmlDocToRef.CreateAttribute("s", "id",
"http://niem.gov/niem/structures/2.0"); attribute.InnerText =
"ID_Person_01" TempElement.SetAttributeNode(attribute);
You can use the following:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<test xmlns='123'/>");
XmlElement e = doc.DocumentElement;
e.Prefix = "a";
Console.WriteLine(doc.InnerXml);
Output:
<a:test xmlns="123" xmlns:a="123" />
Founded in msdn.
Edit:
Since it does not work with your main element you can use .Replace("<", "<Prefixe:")); on your root element as a String. It's not pretty but it does the job.

XmlDocument Prefix Not Being Outputted

I am trying to add a prefix onto a few xmlnodes within a new XMLDocument (Created 100% from scratch, not loaded from a file etc).
In the simplest terms I have this :
XmlDocument doc = new XmlDocument();
XmlElement RootElement = (XmlElement)doc.AppendChild(doc.CreateElement("root"));
foreach (string line in CSV)
{
XmlElement navPointElement = (XmlElement) RootElement.AppendChild(doc.CreateElement("navPoint"));
XmlElement navPointTypeElement =(XmlElement) navPointElement.AppendChild(doc.CreateElement("type"));
navPointTypeElement.Prefix = "acp";
navPointTypeElement.InnerText = nodeCount == 0 ? "cover" : "article";
}
There is much more code but this gives you an idea of what I'm doing. Now the document outputs fine, but it completely skips over the prefix declarations. I have read around about defining namespaces, and I tried to the following to no avail.
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("acp", "http://www.namespace.com");
I'm sure it's something simple, but I can't quite find any documentation on it. The MSDN documentation for xmldocument prefix simply just adds the prefix much the same as I have done without the need for namespaces (Or atleast that's how they show it in their code samples).
Any help is much appreciated :)
Well, you do need a namespace. Something like <acp:type/> is invalid by itself because acp doesn't map to any namespace, which is what a prefix should do.
What you need to do is to set the namespace on the element you want to add on the call of CreateElement for the type element.
public class StackOverflow_10807173
{
public static void Test()
{
XmlDocument doc = new XmlDocument();
XmlElement RootElement = (XmlElement)doc.AppendChild(
doc.CreateElement("root"));
string[] CSV = "hello world how are you".Split(' ');
int nodeCount = 0;
XmlAttribute xmlnsAttr = doc.CreateAttribute(
"xmlns", "acp", "http://www.w3.org/2000/xmlns/");
string acpNamespace = "http://www.namespace.com";
xmlnsAttr.Value = acpNamespace;
RootElement.Attributes.Append(xmlnsAttr);
foreach (string line in CSV)
{
XmlElement navPointElement = (XmlElement)RootElement.AppendChild(
doc.CreateElement("navPoint"));
XmlElement navPointTypeElement = (XmlElement)navPointElement.AppendChild(
doc.CreateElement("type", acpNamespace)); // namespace here
navPointTypeElement.Prefix = "acp";
navPointTypeElement.InnerText = nodeCount == 0 ? "cover" : "article";
}
Console.WriteLine(doc.OuterXml);
}
}
One note: you don't really need to add the namespace in the root element; it's just that if you don't do that, you'll have the xmlns:acp="yournamespace" attribute in all of the type elements (since that prefix isn't in scope). Adding that in a parent element makes adding it in the children elements unecessary.
I had a similar issue, and I found the built-in .NET System.XML objects to be unable to do what I needed.
I needed to use the NAXML markup to create fuel price change records in our POS system. SOME of the elements needed a "nax" prefix, while others didn't. The System.Xml objects seemed to want to add it to all elements or none. I couldn't get it to just apply them to the elements I needed.
Because the System.XML objects didn't give me the granular control I needed, I ended up having to write out the Xml manually using a System.Text.StringBuilder.
Sample code from my app to give you an idea of how to do it:
System.Text.StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
sb.Append("<FuelPriceMaintenanceRequest xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.POSVENDOR.com/NAXML-Extension\" xmlns:nax=\"http://www.naxml.org/POSBO/Vocabulary/2003-10-16\" xsi:schemaLocation=\"http://www.POSVENDOR.com/NAXML-Extension FuelPriceMaintenance.xsd\">\r\n");
sb.Append(" <nax:TransmissionHeader>\r\n");
sb.Append(" <nax:StoreLocationID>" + StoreNumber.ToString() + "</nax:StoreLocationID>\r\n");
sb.Append(" </nax:TransmissionHeader>\r\n");
...snip...
sb.Append("</FuelPriceMaintenanceRequest>");

XmlDocument Remove XMLNS from Root Element

New here, looking to get a little help with my XmlDocument. Is it possible to have string data in my root element AND remove the xmlns= attribute from being shown? I'm looking for something like this:
<Rulebase author=yadda datetime=bingbang version=1.x </Rulebase>
When I try to use my string data by doing:
xmlDom.AppendChild(xmlDom.CreateElement("", "Rulebase", data));
XmlElement xmlRoot = xmlDom.DocumentElement;
It ends up looking like this:
<Rulebase xmlns="version=0 author=username date=7/13/2011 </Rulebase>
and it also appends xmlns="" to all my other nodes.
The CreateElement overload you're using takes a prefix as it's first argument, local name as second, and namespace as third. If you don't want a namespace, don't use this overload. Just use the one that takes a local name as the one and only argument. Then add your data separately as child elements and attributes.
var xmlDom = new XmlDocument();
XmlElement root = xmlDom.CreateElement("Rulebase");
xmlDom.AppendChild(root);
XmlElement data = xmlDom.CreateElement("Data");
root.AppendChild(data);
XmlAttribute attribute = xmlDom.CreateAttribute("author");
attribute.Value = "username";
data.Attributes.Append(attribute);
attribute = xmlDom.CreateAttribute("date");
attribute.Value = XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind);
data.Attributes.Append(attribute);
Console.WriteLine(xmlDom.OuterXml);
Creates (formatting added)
<Rulebase>
<Data author="username" date="2011-07-13T22:44:27.5488853-04:00" />
</Rulebase>
Using XmlDocument to generate XML is pretty tedious though. There are many better ways in .NET, like XmlSerializer and DataContractSerializer. You can also use Linq-to-Xml and XElement. Or you can use an XmlWriter.Create(). Lots of options.

Categories

Resources