使用 XElement 创建带前缀的 XML 元素

Posted

技术标签:

【中文标题】使用 XElement 创建带前缀的 XML 元素【英文标题】:Creating an XML element with a prefix using XElement 【发布时间】:2012-10-22 13:48:08 【问题描述】:

我有一个使用包含多个 WPF 自定义组件的画布的应用程序。我想将这些组件导出到一个 XAML 文件中,以便另一个应用程序可以获取它,但是为了做到这一点,我需要为导出的组件添加前缀限定符。例如,如果我要导出一个 FrequencyButtonA 组件,我需要输出类似

<PanelControls:FrequencyButtonA Frequency="113.123" Width="250"/>

我尝试了以下方法,但由于使用了 ':' 字符而出现异常:

return new XElement("PanelControls:" + "FrequencyButtonA");

有什么想法吗?我在 SO 中发现了一些其他问题,这些问题似乎与我遇到的问题相似(例如,this link),但不是完全相同的情况。

提前致谢!

编辑 - 更多背景信息:这是我需要生成的完整输出的示例:

<Border x:Name="CommsPanelBorder"
    Style="DynamicResource BorderTemplate"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:PanelControls="clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"
    VerticalAlignment="Top">
        <PanelControls:FrequencyButtonB Frequency="113.123" Width="250"/>
        <PanelControls:FrequencyButtonA Frequency="102.3" Width="150"/>

我忘记在我的原始帖子中提到根节点(边框)是在方法中创建的。然后该方法循环遍历放置在画布中的所有元素,并在所述元素上调用一个方法,该方法返回一个 XElement,该 XElement 稍后将添加到根节点。因此,我需要让 XElements 能够自己创建。该方法的代码如下:

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "PanelControls";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "DynamicResource BorderTemplate"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        IEnumerable<CommsPanelControl> commsPanelControls = editCanvas.Children.OfType<CommsPanelControl>();

        foreach (var commsPanelControl in commsPanelControls)
        
            XElement xElement = commsPanelControl.AddXElement(root, ns);
            root.Add(xElement);
        

编辑 2. 添加了一些代码,以便 Reinder 可以看到我当前的方法:

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "PanelControls";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "DynamicResource BorderTemplate"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        XElement xElement = new XElement(ns + "FrequencyButtonA",
            new XAttribute("Frequency", "113.123"),
            new XAttribute("Width", "250"));
        root.Add(xElement);

编辑 3. 作为参考,这是我的问题的可能解决方案。感谢 Reiner 的意见!

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "DynamicResource BorderTemplate"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        XElement xElement = new XElement(ns + "FrequencyButtonA",
            new XAttribute("Frequency", "113.123"),
            new XAttribute("Width", "250"));
        root.Add(xElement);

【问题讨论】:

【参考方案1】:

PanelControls 这样的前缀只有在声明与之相关的命名空间时才有意义。

您需要在节点本身或例如在根中指定它。

// create the root element, with the 'PanelControls' namespace
XNamespace nSpace = "PanelControls";
XElement element = new XElement("root",
          new XAttribute(XNamespace.Xmlns + "PanelControls", nSpace));

element.Add(addXElement("FrequencyButtonA", nSpace ));

...

private static XElement addXElement(string n, XNamespace ns)

    return new XElement(ns + n,
        new XAttribute("Frequency", 113.123),
        new XAttribute("Width", 250));

方法 'addXElement()' 将在命名空间 ns 中创建新的 XElement,因此您最终会得到:

<?xml version="1.0"?>
<root xmlns:PanelControls="PanelControls">
    <PanelControls:FrequencyButtonA Width="250" Frequency="113.123"/>
</root>

【讨论】:

感谢您的回复,但我希望输出更紧凑,例如我发布的那个。我了解您的解决方案有效,但我希望生成的 XAML 尽可能简洁。你能建议一种方法来获得像我的帖子中那样的输出吗? 你稍后用返回的 XElement 做什么? 我将它添加到根元素。目前,我在一个函数中创建了根对象(它是一个画布),然后遍历它包含的所有元素,并在每个元素上调用一个实例方法,以便将它们自己作为 XElement 返回,然后附加到根。 那么您必须在该根对象上定义命名空间,就像 ghost 所说的那样。我已经更新了答案 感谢您的回复。我不明白的一件事是如何修改代码,使 PanelControls 命名空间前缀指向“clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib”。我已经通过第二次编辑更新了我的原始帖子,其中我展示了我根据您的解决方案完成的快速测试。程序编译,但 FrequencyButtonA 的输出不是我想要的。这就是我得到的: 有什么想法吗?【参考方案2】:
using System;
using System.Xml.Linq;


class Program

    static void Main(string[] args)
    

        XNamespace @namespace = "PanelControls";
        XElement element = new XElement("root",
            new XAttribute(XNamespace.Xmlns + "PanelControls", @namespace),
            new XElement(@namespace + "FrequencyButtonA",
                new XAttribute("Frequency", 113.123),
                new XAttribute("Width", 250)));
        Console.WriteLine(element);
    

【讨论】:

感谢您的回复。您的解决方案输出了我需要的 FrequencyButtonA 代码,但是,我忘记在我的原始帖子中提到根元素是在不同的位置创建的,然后各个元素(例如频率按钮)被创建为 stadalone XElement 实例被添加到根目录。创建根元素后,有什么方法可以输出类似于我在原始帖子中提供的示例的内容?我尝试了不同的方法,但我得到了一个非常冗长的输出,我想保持输出紧凑。

以上是关于使用 XElement 创建带前缀的 XML 元素的主要内容,如果未能解决你的问题,请参考以下文章

C#用命名空间前缀编写XElement,但不包括根元素中的前缀

在 XElement WriteTo 方法中,强制 XmlWriter 为具有已定义 xmlns 属性的子元素使用前缀

XElement 使用介绍

在 C# 中使用 XElement 获取 XML 的元素节点值

如何创建带前缀的 XmlElement 属性?

VB.NET:使用 XDocument 在 XML 文件中添加/编辑/删除 XElement