TL/DR: What's the easiest method to change the namespace value using LINQ to XML
, say from xmlns:gcs="clr-namespace:NsOne;assembly=AsmOne"
to xmlns:gcs="clr-namespace:NsTwo;assembly=AsmTwo"
?
Why? because:
I serialized Xaml
using System.Windows.Markup.XamlWriter.Save(myControl)
. I want to visualize this GUI appearance somewhere else (deserializing using System.Windows.Markup.XamlReader.Parse(raw)
), in another project.
I don't want to link to the original assembly!
I just need to change the namespace, so XamlReader.Parse(raw)
won't throw an exception. I currently do it using regular-expressions and it works, but I don't like that method (e.g. if I have xmlns:gcs="clr-namespace:NsOne;assembly=AsmOne"
inside a CDATA
)
This is my serialized Xaml
:
<FlowDocument PagePadding="5,0,5,0" AllowDrop="True"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:gcs="clr-namespace:NsOne;assembly=AsmOne"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<gcs:MyParagraph Margin="0,0,0,0">
<gcs:MyParagraph.MetaData>
<gcs:ParagraphMetaData UpdaterParagraphUniqueId="1" />
</gcs:MyParagraph.MetaData>
<Span>some text...</Span>
</gcs:MyParagraph>
<gcs:MyParagraph Margin="0,0,0,0" Background="#FFF0F0F0">
<gcs:MyParagraph.MetaData>
<gcs:ParagraphMetaData UpdaterParagraphUniqueId="2" />
</gcs:MyParagraph.MetaData>
<Span Foreground="#FF0000FF">some more text...</Span>
</gcs:MyParagraph>
</FlowDocument>
(MyParagraph
and ParagraphMetaData
are custom types and they both exist at the source assembly and the destination assembly. MyParagraph
inherits WPF
's Paragraph
)
You can just parse the whole XML as a string and insert namespaces where appropriate. This solution, however, can create lots of new strings only used within the algorithm, which is not good for the performance.
Contains the classes for LINQ to XML. LINQ to XML is an in-memory XML programming interface that enables you to modify XML documents efficiently and easily.
When using prefixes in XML, a namespace for the prefix must be defined. The namespace can be defined by an xmlns attribute in the start tag of an element. The namespace declaration has the following syntax. xmlns:prefix="URI".
This is fairly easy to do.
var doc = XDocument.Parse(raw);
XNamespace fromNs = "clr-namespace:NsOne;assembly=AsmOne";
XNamespace toNs = "clr-namespace:NsTwo;assembly=AsmTwo";
// redefines "gcs", but doesn't change what namespace the elements are in
doc.Root.SetAttributeValue(XNamespace.Xmlns + "gcs", toNs);
// this actually changes the namespaces of the elements from the old to the new
foreach (var element in doc.Root.Descendants()
.Where(x => x.Name.Namespace == fromNs))
element.Name = toNs + element.Name.LocalName;
Both portions are needed to result in XAML that's both correct and easily-readable, because the namespace of the elements is stored separately from the xmlns
declarations in an XDocument
. If you only change what "gcs" means, then it will write xmlns
statements to keep the elements in their old namespace. If you only change what namespace the elements are in, then it will include xmlns="clr-namespace:NsTwo;assembly=AsmTwo"
statements as necessary, and ignore gcs
(which will still reference the old NsOne
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With