使用LINQ to XML更改命名空间值的最简单方法是什么?

时间:2013-12-30 15:33:00

标签: c# xml xaml serialization xml-namespaces

TL / DR:使用LINQ to XML更改名称空间值的最简单方法是什么,比如从xmlns:gcs="clr-namespace:NsOne;assembly=AsmOne"xmlns:gcs="clr-namespace:NsTwo;assembly=AsmTwo"

为什么呢?这是因为:

我使用Xaml序列化System.Windows.Markup.XamlWriter.Save(myControl)。我想在另一个项目中将这个GUI外观可视化到其他地方(使用System.Windows.Markup.XamlReader.Parse(raw)进行反序列化)。

我不想链接到原始程序集!

我只需要更改命名空间,因此XamlReader.Parse(raw)不会抛出异常。我目前使用正则表达式来运行,但我不喜欢这种方法(例如,如果我xmlns:gcs="clr-namespace:NsOne;assembly=AsmOne"内有CDATA

这是我序列化的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>

MyParagraphParagraphMetaData是自定义类型,它们都存在于源程序集和目标程序集中。MyParagraph继承WPF的{​​{1}})

1 个答案:

答案 0 :(得分:6)

这很容易做到。

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;

这两个部分都需要导致XAML正确且易于阅读,因为元素的名称空间与xmlns中的XDocument声明分开存储。如果您只更改“gcs”的含义,那么它将编写xmlns语句以将元素保留在旧的命名空间中。如果您只更改元素所在的命名空间,那么它将根据需要包含xmlns="clr-namespace:NsTwo;assembly=AsmTwo"个语句,并忽略gcs(它仍会引用旧的NsOne)。