How to set namespace on XDocument - c#

I need to acсess xml file. But xml have base namespace whith prefix m:
This is my code, but it do not working, write NullRefference exeptions:
var fileКс = XDocument.Load(somePath);
var allDescrioptions = fileКс.Root.Element("formulas").Elements("formula").ToList();
This is part of xml file:
<?xml version="1.0" encoding="utf-8" ?>
<m:math xmlns:m="http://www.kontur-extern.ru/ФНС 4.0/math.xsd">
<m:formulas>
<m:formula target="#ПрибУб" match="/Файл/Документ/Прибыль/РасчНал" source="Лист 02/стр.060">
</m:formula>
</m:formulas>
</m:math>
I think need to specify namespace, but I don't know how

You can use XNamespace as follow :
XNamespace m = "http://www.kontur-extern.ru/ФНС 4.0/math.xsd";
var fileКс = XDocument.Load(somePath);
var allDescrioptions = fileКс.Root.Element(m+"formulas").Elements(m+"formula").ToList();

Related

Access Child nodes with namespace using xpath

How can I read the content of the childnotes using Xpath?
I have already tried this:
var xml = new XmlDocument();
xml.Load("server-status.xml");
var ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "namespace");
var node = xml.SelectSingleNode("descendant::ns:server[ns:ip-address]", ns)
Console.WriteLine(node.InnerXml)
But I only get a string like this:
<ip-address>127.0.0.50</ip-address><name>Server 1</name><group>DATA</group>
How can I get the values individually?
Xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server-status xmlns="namespace">
<server>
<ip-address>127.0.0.50</ip-address>
<name>Server 1</name>
<group>DATA</group>
</server>
</server-status>
You're using XML namespaces in XPath correctly.
However, your original XPath,
descendant::ns:server[ns:ip-address]
says to select all ns:server elements with ns:ip-address children.
If you wish to select the ns:ip-address children themselves, instead use
descendant::ns:server/ns:ip-address
Similarly, you could select ns:name or ns:group elements.

How do I get an attribute with namespace?

<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Element xsi:Attribute="Test"></Element>
</Root>
I'm trying to read the "xsi:Attribute" attribute; the code is like this:
var doc = XDocument.Load(new StringReader(xmlText));
var node = doc.Root.Descendants().First();
XNamespace myNamespace = "xsi";
var attribute = node.Attributes(myNamespace + "Attribute").First();
It throws a "Sequence contains no elements" exception in the last line. What am I doing wrong?
You need to use the actual namespace, not "xsi", which is just a local lookup within the XML file itself for the real namespace:
XNamespace myNamespace = "http://www.w3.org/2001/XMLSchema-instance";
Try this (I believe its more generic):
XNamespace myNamespace = doc.Root.GetNamespaceOfPrefix("xsi");

How to read namespaces c# LINQ to XML

How to read namespaces from code? I want to get xmlns:es, xmlns:un, xmlns:xn attribute values, but I get null attributes, How do I read it?
I try like this:
XNamespace xmlns = xdoc.Root.Attribute("xmlns").Value;
XNamespace ES = xdoc.Root.Attribute(xmlns + "es").Value;
XML:
<?xml version="1.0" encoding="UTF-8"?>
<xmlFile xmlns:es="my.xsd"
xmlns="not_my.xsd">
...
</xmlFile>
XNamespace defns = xdoc.Root.GetDefaultNamespace();
XNamespace es = xdoc.Root.GetNamespaceOfPrefix("es");

Add namespaces to serialized xml

I've got a pretty nasty problem with xml serialization - I need to add some special information to the resulting xml-file:
Currently, it looks like
<?xml version="1.0" encoding="iso-8859-1"?>
<ORDER_LIST>
<ORDER version="1.0" xmlns="http://www.opentrans.org/XMLSchema/1.0">... shortened ...</ORDER>
<ORDER version="1.0" xmlns="http://www.opentrans.org/XMLSchema/1.0">... shortened ...</ORDER>
<ORDER version="1.0" xmlns="http://www.opentrans.org/XMLSchema/1.0">... shortened ...</ORDER>
</ORDER_LIST>
but it should look like
<?xml version="1.0" encoding="iso-8859-1"?>
<ORDER_LIST>
<ORDER xmlns="http://www.opentrans.org/XMLSchema/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opentrans.org/XMLSchema/1.0 openTRANS_ORDER_1_0_all_in_one.xsd" version="1.0" type="standard">... shortened ...</ORDER>
<ORDER xmlns="http://www.opentrans.org/XMLSchema/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opentrans.org/XMLSchema/1.0 openTRANS_ORDER_1_0_all_in_one.xsd" version="1.0" type="standard">... shortened ...</ORDER>
<ORDER xmlns="http://www.opentrans.org/XMLSchema/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opentrans.org/XMLSchema/1.0 openTRANS_ORDER_1_0_all_in_one.xsd" version="1.0" type="standard">... shortened ...</ORDER>
</ORDER_LIST>
The additional namespace (xmlns:xsi) and the xsi:schemaLocation / type attributes should be added to the result.
Actually my code is:
[XmlTypeAttribute(Namespace="http://www.opentrans.org/XMLSchema/1.0")]
public class OrderContainer
{
[XmlElementAttribute("ORDER")]
public List<ORDER> orderList;
}
---- snip ----
string xmlString;
XmlWriterSettings settings = new XmlWriterSettings()
{
Encoding = Encoding.GetEncoding("ISO-8859-1"),
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
ConformanceLevel = ConformanceLevel.Document,
};
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
var testOrder = new ORDER();
var orderContainer = new OrderContainer();
orderContainer.orderList = new List<ORDER>();
orderContainer.orderList.Add(testOrder);
XmlSerializer serializer = new XmlSerializer(typeof(List<ORDER>), new XmlRootAttribute("ORDER_LIST"));
using (MemoryStream ms = new MemoryStream())
{
using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
serializer.Serialize(writer, orderList, ns);
xmlString = Encoding.ASCII.GetString(ms.ToArray());
}
Console.WriteLine(xmlString);
It works really fine - except for the namespaces and attributes on the ORDER elements.
Background-information: The ORDER class is created from the openTrans-definition (opentrans_order_1_0_all_in_one.xsd).
It's been translated into C# classes using Xsd2Code (Xsd2Code).
Because of the automatic generation, adorning the class with attributes is not easily possible - I guess?
Thanks for any hint!
(Edited some information)
I know its a little late to reply to this question, but nonetheless I am answering in case someone in need stumbles upon this question.
I order to add namespaces you need to use this class: System.Xml.Serialization. XmlSerializerNamespaces, which I see in the problem code that it has been defined.
Following is the syntax that I have used to add namespaces while dealing with the xCBL Xml Schema:
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlns; //Defined as the Field of the class you want to serialize
//Defined in the Constructor
xmlns = new XmlSerializerNamespaces();
xmlns.Add("core", "rrn:org.xcbl:schemas/xcbl/v4_0/core/core.xsd");
This will add the namespace in the generated Xml like this:
xmlns:core="rrn:org.xcbl:schemas/xcbl/v4_0/core/core.xsd"
What it should look like is:
<?xml version="1.0" encoding="iso-8859-1"?>
<ORDER_LIST xmlns:trans="http://www.opentrans.org/XMLSchema/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opentrans.org/XMLSchema/1.0 http://www.opentrans.org/XMLSchema/1.0 openTRANS_ORDER_1_0_all_in_one.xsd" version="1.0" >
<trans:ORDER type="standard" >... shortened ...</ORDER>
<trans:ORDER type="standard" >... shortened ...</ORDER>
<trans:ORDER type="standard" >... shortened ...</ORDER>
</ORDER_LIST>
I'm not familar with xsd2code, but if you were hand coding, you need to put attributes.
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.opentrans.org/XMLSchema/1.0")]
[System.Xml.Serialization.XmlElementAttribute("Order")]
public class Order() {
String Type
}
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.opentrans.org/XMLSchema/1.0")]
[System.Xml.Serialization.XmlRootAttribute("OrderList", Namespace="http://www.opentrans.org/XMLSchema/1.0", IsNullable=false)]
public class OrderList() {
List<Orders>
}
try this. it's a libary to create or read opentrans documents!
http://opentrans.wordpress.com/

How to correctly parse an XML document with arbitrary namespaces

I am trying to parse somewhat standard XML documents that use a schema called MARCXML from various sources.
Here are the first few lines of an example XML file that needs to be handled...
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd">
<marc:record>
<marc:leader>00925njm 22002777a 4500</marc:leader>
and one without namespace prefixes...
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<collection xmlns="http://www.loc.gov/MARC21/slim">
<record>
<leader>01142cam 2200301 a 4500</leader>
Key point: in order to get the XPaths to resolve further along in the program I have to go through a regex routine to add the namespaces to the NameTable (which doesn't add them by default). This seems unnecessary to me.
Regex xmlNamespace = new Regex("xmlns:(?<PREFIX>[^=]+)=\"(?<URI>[^\"]+)\"", RegexOptions.Compiled);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlRecord);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable);
MatchCollection namespaces = xmlNamespace.Matches(xmlRecord);
foreach (Match n in namespaces)
{
nsMgr.AddNamespace(n.Groups["PREFIX"].ToString(), n.Groups["URI"].ToString());
}
The XPath call looks something like this...
XmlNode leaderNode = xmlDoc.SelectSingleNode(".//" + LeaderNode, nsMgr);
Where LeaderNode is a configurable value and would equal "marc:leader" in the first example and "leader" in the second example.
Is there a better, more efficient way to do this? Note: suggestions for solving this using LINQ are welcome, but I would mainly like to know how to solve this using XmlDocument.
EDIT: I took GrayWizardx's advice and now have the following code...
if (LeaderNode.Contains(":"))
{
string prefix = LeaderNode.Substring(0, LeaderNode.IndexOf(':'));
XmlNode root = xmlDoc.FirstChild;
string nameSpace = root.GetNamespaceOfPrefix(prefix);
nsMgr.AddNamespace(prefix, nameSpace);
}
Now there's no more dependency on Regex!
If you know there is going to be a given element in the document (for instance the root element) you could try using GetNamespaceOfPrefix.

Categories

Resources