-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LINQ to XML: Inconsistent namespace prefix handling #48400
Comments
Tagging subscribers to this area: @buyaa-n, @krwq Issue DetailsDescriptionI'm experiencing inconsistent behavior regarding XML namespace prefixing. When I create an XElement via original: <html xmlns:mn="http://my-namespace.com/">
<mn:p>text</mn:p>
<p xmlns="http://my-namespace.com/">text</p>
</html> namespace MyNamespace
{
using System.Xml.Linq;
using Xunit;
public class XmlParsing
{
private const string Prefix = "mn";
private static readonly XNamespace Namespace = "http://my-namespace.com/";
[Fact]
public void Fact()
{
var root = new XElement("html", new XAttribute(XNamespace.Xmlns + Prefix, Namespace));
var original = new XElement(Namespace + "p", "text");
var deserialized = XElement.Parse(original.ToString());
Assert.Equal(original.ToString(), deserialized.ToString());
root.Add(original);
root.Add(deserialized);
Assert.Equal(original.ToString(), deserialized.ToString());
}
}
} I would expect the namespace prefixing to work identical no matter how the I also created a gist containing above code to demonstrate the issue. ConfigurationAbove code is running in a netcoreappe3.1 with C# 8.0 nullable enabled on a Windows 10 Pro x64 Regression?Other information
|
The order of operation appears to matters here. If If you change your source like so you receive the intended behavior:
Not sure if this helps in the interim. |
@watfordgnf thanks for the suggestion. Unfortunately in the real use case, I don't have access to the root element at this level. Only later will it be composed from all the different parts making up the complete XML. |
In both cases
It appears runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs Lines 206 to 209 in 247212f
That call to runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs Lines 306 to 325 in 247212f
Without any ancestors That was also a long way of saying that the specific binding is being lost when reading it in (lines 907 and 912): runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs Lines 902 to 916 in 9195df6
I'm not quite sure how you could change |
I was hoping that I could work around this by using |
@philippdolder you can workaround this by cleaning all namespace declarations after deserialization: deserialized.DescendantsAndSelf().Attributes().Where(a => a.IsNamespaceDeclaration).Remove(); or by adding all required prefixes before serialization: original.SetAttributeValue(XNamespace.Xmlns + Prefix, Namespace.NamespaceName);
No, it's how XML designed. The isolated string |
@mayorovp Thanks for the hints
I'm not claiming this string in isolation is valid xml though. I'm totally aware that in isolation it needs to have the namespace prefix declaration inside the tag itself. |
Can you repro this with XDocument rather than XElement? If not I'm leaning to close this as "by design" |
This test still fails with the same error.
|
@philippdolder can you edit the first post here to summarize this thread with latest info to make it easier for anyone to pick this up? Would be nice to add some justification why do you think this behavior is better and comments with what are the values on each assert |
@krwq done. and it seems the bot changed labels and moved the issue around again |
@philippdolder thanks! No worries about the bot. As for this issue to set the expectations: I'm not sure this will get fixed - currently even though it doesn't roundtrip with serialization both XMLs are equivalent - all elements have the same local name and the namespace and the content and the difference is just the prefix which doesn't have any meaning and just improves readability. Perhaps some knobs in the serialization which would allow roundtripping might be a better solution than a re-design... |
Unfortunately, I think this is a design flaw in LINQ to XML. The .NET traditional XML DOM implementation maintains the original element and attribute prefixes: XmlElement.Prefix and XmlAttribute.Prefix. While you can call I'm writing an application to implement semantic equality using LINQ to XML and this shortcoming has caused some pain points. For example, if I have superfluous namespace declarations (which is perfectly valid xml), LINQ to XML only picks up the first one doesn't maintain records of all of the superfluous/duplicates. For example (from 3.5 Superfluous Namespace declarations, the following is possible and legal/valid xml but it is impossible to canonicalize according to the spec using LINQ to XML because of this "namespace aggregation". Note that all namespace declarations point to the same namespace but just use different prefixes:
I'd love to see a fix here! |
Description
Note: this post has been edited to summarize the whole discussion.
I'm experiencing inconsistent behavior regarding XML namespace prefixing. When I create an XElement via
new XElement()
the code behaves differently from when I useXElement.Parse()
to parse the equivalent XML structure.See code sample below. The first assert succeeds. The second assert fails.
The
root
element knows about the namespace prefixing. After adding both elements to it, only the one created with the constructor gets prefixed properly. See string representations of each object as they are at the end of theFact
method.original:
<mn:p xmlns:mn="http://my-namespace.com/">text</mn:p>
deserialized:
<p xmlns="http://my-namespace.com/">text</p>
root:
I would expect the namespace prefixing to work identical no matter how the
XElement
is created.Using
XDocument
instead, leads to the same error.I also created a gist containing above code to demonstrate the issue.
Configuration
Above code is running in a netcoreappe3.1 with C# 8.0 nullable enabled on a Windows 10 Pro x64
Regression?
Other information
The only work around I found is to explicitly add thenew XAttribute(XNamespace.Xmlns + Prefix, Namespace)
attribute to the original XElement. Since the xml I'm trying to parse is not 100% under our control, this will not work in the real world scenario.Doesn't really work, as the resulting xml will contain unnecessary namespace prefix declarations
The text was updated successfully, but these errors were encountered: