Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the easiest method to change the namespace value using LINQ to XML?

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)

like image 566
Tar Avatar asked Dec 30 '13 15:12

Tar


People also ask

How do I change a namespace in XML?

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.

Which namespace contains classes related to LINQ to XML?

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.

How do I add namespace prefix to XML element?

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".


1 Answers

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).

like image 123
Tim S. Avatar answered Sep 19 '22 18:09

Tim S.