I have a XDocument with the following structure where I want to add a bunch of XElements.
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr>
...
</GrpHdr>
<!-- loaded nodes go here -->
<CstmrCdtTrfInitn>
</Document>
The XElements have the following structure:
<PmtInf xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
...
</PmtInf>
The problem is that the namespace in child nodes is not supported at the recipients side and since it is the same as the XDocument's namespace - it is redundant. How do I avoid/remove that namespace on the child nodes?
The code that I use right now:
var childNodes = new XElement(NameSpace + "GrpHdr", ...);
XElement[] loadedNodes = ...;//Loads from a service using XElement.Load
var content = new XElement(NameSpace + "CstmrCdtTrfInitn", childNodes,loadedNodes));
When calling Save on XElement or XDocument, there is a flags enum SaveOptions that allow you to control to some extent how the document is written to XML.
The easiest way to achieve what you want (without traversing the structure to remove the redundant attributes) is to use one of these flags: OmitDuplicateNamespaces.
Remove the duplicate namespace declarations while serializing.
You can see in this fiddle that adding this flag changes my example output from this:
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr />
<PmtInf xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">...</PmtInf>
</CstmrCdtTrfInitn>
</Document>
To this:
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr />
<PmtInf>...</PmtInf>
</CstmrCdtTrfInitn>
</Document>
Related
I am struggling with parsing XPathDocument with XPathNavigator where XML document contains xmlns tag, but no namesapce prefix is used.
<?xml version="1.0" encoding="UTF-8"?>
<Order version="1" xmlns="http://example.com">
<Data>
<Id>1</Id>
<b>Aaa</b>
</Data>
</Order>
SelectSingleNode method requires namespace manager with namespace defined.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nav.NameTable);
nsmgr.AddNamespace("ns","http://example.com");
As a result I have to start using ns prefix in all XPath expressions, although the original XML file does not use prefixes, for e.g.:
nav.SelectSingleNode("/ns:Order/ns:Data/ns:Id", nsmgr)
This adds an unnecessary complexity.
Is there any way to push XPathNavigator to ignore namespace and its prefixes? Ot at least use of prefixes, as namespace definition itself exists only once, so not much effort
The XML has a default namespace. So each and every XML element is bound to it, visible or not.
It is better to use LINQ to XML.
It is a preferred XML API, and available in the .Net Framework since 2007.
c#
void Main()
{
XDocument xdoc = XDocument.Parse(#"<Order version='1' xmlns='http://example.com'>
<Data>
<Id>1</Id>
<b>Aaa</b>
</Data>
</Order>");
XNamespace ns = xdoc.Root.GetDefaultNamespace();
foreach (XElement elem in xdoc.Descendants(ns + "Data"))
{
Console.WriteLine("ID: {0}, b: {1}"
, elem.Element(ns + "Id")?.Value
, elem.Element(ns + "b")?.Value);
}
}
Following is the XML format:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" unique-identifier="isbn0000000000000" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Eltern Family</dc:title>
<dc:creator></dc:creator>
<dc:publisher></dc:publisher>
<dc:rights></dc:rights>
<dc:identifier id="isbn0000000000000">0000000000000</dc:identifier>
<dc:language>de</dc:language>
<dc:date opf:event="publication">2019-02-11</dc:date>
</metadata>
</package>
Here I got the default Namespace by XDocument.Root.GetDefaultNamespace();. But as you can see, there are multiple namespaces in the <metadata> XML node. The problem is that, they are variable i.e., each XML may have different values, so I cannot declare a variable with one fixed value.
How do I get the namespaces, so that I can add values to the descendant elements?
Please help.
Regards
Aman
If, as you say, you want to set the content of dc:rights, then you need to get hold of that element.
You can do this by name - the 'qualified name' is made of of the namespace and a local name. The namespace prefix dc is not actually important in and of itself, it's just used as a shorthand to refer to the namespace within the document.
Assuming you have parsed this XML to an XDocument called doc:
XNamespace dc = "http://purl.org/dc/elements/1.1/"
var rights = doc.Descendants(dc + "rights").Single();
rights.Value = "text";
I'm trying to create some xml nodes runtime using XPath for C#. See XML Below:
<Package xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest" xmlns="http://schemas.microsoft.com/appx/2010/manifest">
<Application>
<m2:VisualElements>
<!--- INSERT CHILD NODES HERE WHICH ALSO HAVE NAMESPACE 'm2' ---->
</m2:VisualElements>
</Application>
</Package>
Currently I'm doing the following:
XElement visualElements = doc.Descendants().SingleOrDefault(p => p.Name.LocalName == "VisualElements");
visualElements.Add(new XElement(doc.Root.GetDefaultNamespace() + "InitialRotationPreference"));
I know that this is wrong since I reference the default namespace, this will result in this being added:
<InitialRotationPreference />
When I want:
<m2:InitialRotationPreference />
Is there some way to access the parent-nodes namespace (m2) without "knowing" the prefix or the namespace-url?
Thank you!
Your document root's namespace is http://schemas.microsoft.com/appx/2010/manifest. Use the one from VisualElements:
XName name = visualElements.Name.Namespace + "InitialRotationPreference"
Or specify explicitly:
XName name = XName.Get("InitialRotationPreference",
"http://schemas.microsoft.com/appx/2013/manifest");
Then add an element with that name:
visualElements.Add(new XElement(name));
I am trying to read the entitysets within the EDMX file from Entity Framework.
The EDMX file (XML format) has the following layout:
<edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
<edmx:Runtime>
<edmx:ConceptualModels>
<Schema Namespace="Model" Alias="Self" p1:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:p1="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<EntityContainer Name="EntityModel" p1:LazyLoadingEnabled="true">
<EntitySet Name="TableName" EntityType="Model.TableName" />
I am using following XPath to get all EntitySet Nodes within the EntityContainer:
/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/Schema/EntityContainer/EntitySet
but I am getting no result with this C# code:
XmlDocument xdoc = new XmlDocument("pathtoedmx");
var ns = new XmlNamespaceManager(xdoc.NameTable);
ns.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2009/11/edmx");
ns.AddNamespace("annotation", "http://schemas.microsoft.com/ado/2009/02/edm/annotation");
ns.AddNamespace("p1", "http://schemas.microsoft.com/ado/2009/02/edm/annotation");
ns.AddNamespace("", "http://schemas.microsoft.com/ado/2009/11/edm");
var entitySets = xdoc.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/Schema/EntityContainer/EntitySet", ns);
Already got the XPath from this tool (http://qutoric.com/xmlquire/), because I started not trusting my own XPath skills but it tells me the same XPath I was already using.
If I remove the "/Schema/EntityContainer/EntitySet" part its finding the "/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels", but not further on already tried to specify the "edmx" namespace ("edmx:/Schema") but no difference.
Hope you can help me out, already banging my head against the table. :)
Namespaces are a convention on how to combine two different XML dialects into a single document. Those prefixes really doesn't matter as long you keep your URI component exactly the same. For instance, take something like this:
ns.AddNamespace("xxx", "http://schemas.microsoft.com/ado/2009/11/edmx");
Console.WriteLine(xdoc.SelectNodes("/xxx:Edmx", ns).Count); // 1
You'll get one node because your namespace URI matched, despite your "wrong" namespace prefix.
If you have an attribute named xmlns, current element and it's children will inherits that namespace URI.
In your case, your root element doesn't have a default namespace and that's ok. But your Schemas element does have a namespace and you need to inform it. I came with this code:
// change "" to "edm"
ns.AddNamespace("edm", "http://schemas.microsoft.com/ado/2009/11/edm");
var entitySets = xdoc.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/edm:Schema/edm:EntityContainer/edm:EntitySet", ns);
I'm currently having trouble deleting a troublesome attribute from my Xdocument's root node: xml:base.
My Xdocument currentDoc:
<root xml:base="texthere">
<child/>
</root>
I looked at the documentation about xml:base here: http://www.w3.org/TR/xmlbase/.
I'm having trouble in my C# code to get rid of this because this xml: prefix doesn't have a declaration like other namespace prefixes.
This is what I have which isn't working:
currentDoc.Root.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
The "xml" namespace is defined:
currentDoc.Root.Attributes(XNamespace.Xml + "base").Remove();