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

天大地大妈咪最大 提交于 2019-12-23 09:48:04

问题


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)


回答1:


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



来源:https://stackoverflow.com/questions/20842531/whats-the-easiest-method-to-change-the-namespace-value-using-linq-to-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!