使用 c# 在属性级别读取带有名称空间的 XML

Posted

技术标签:

【中文标题】使用 c# 在属性级别读取带有名称空间的 XML【英文标题】:Reading the XML with namespaces at attribute level using c# 【发布时间】:2019-03-09 14:45:08 【问题描述】:

我有一个如下的 XML 文件

<?xml version="1.0"?>
<appSettings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <add xdt:Transform="Replace" xdt:Locator="Match(key)" key="Key1" value="TransformValue1"/>
  <add xdt:Transform="Replace" xdt:Locator="Match(key)" key="Key2" value="TransformValue2"/>
  <add xdt:Transform="Replace" xdt:Locator="Match(key)" key="Key3" value="TransformValue3"/>
  <add xdt:Transform="Replace" xdt:Locator="Match(key)" key="Key4" value="TransformValue4"/>

  <add xdt:Transform="Insert" key="Key6" value="TransformValue6"/>
</appSettings>

我想将此 XML 作为类 Key 的列表。这里的Key类如下

[Serializable]
public class Key

    public string Key  get; set; 
    public string Value  get; set; 
    public string Transform  get; set; 
    public string Locator  get; set; 

请推荐

大家好,为了更好地理解我的问题,我有目的地更新问题。

目的: 作为自动部署的一部分,我们还计划自动部署 web.config 文件。为了实现这个过程,我们使用了“Web config transform”的概念。 为了实现这种“Web 配置转换”,我们将在集中式服务器中维护转换文件(所有实例和客户端),这些文件将用于转换。 但是为了更新转换文件,我们为部署团队成员提供了 Ui。为此,我们需要读取带有名称空间的 XML 配置。

【问题讨论】:

您能解释一下您要解决什么问题吗?为什么要使用自定义类而不是 ConfigurationManager 类从配置文件中提取信息? 您好 Chandramouli,您能详细介绍一下您的问题吗? 大家好,这不是实际的 web.config 文件。这是我们将在受保护服务器中维护的转换配置(不会在版本控制工具中提交)。我想为部署团队成员提供一个 UI 来更新这些文件。所以我们需要把它作为 list 对象。 介意分享不起作用的序列化代码吗? 【参考方案1】:

我会为这种方法使用 XmlDocument。一个原因是,您可以简单地选择要使用的所有标签(在您的情况下为 add)。其次,使用foreach 循环,您可以通过Attributes 调用轻松获取所有值

XmlDocument xdoc = new XmlDocument();

xdoc.LoadXml("YourXmlString");

XmlNodeList xNodes = xdoc.GetElementsByTagName("add");


foreach(XmlNode item in xNodes)
    
    key = item.Attributes["state"].Value;

    //and so on

希望能解决你的问题

【讨论】:

这里的问题是如何获取具有命名空间的属性值(如 xdt:Transform 和 xdt:Locator)。 我不知道你在问什么,你能指点我吗? 在您的逻辑中,如果我想获取属性 xdt:Transform 和 xdt:Locator 的值,系统将通过一个名为“对象引用未设置为对象实例”的错误 @Chandramouli 我复制了您的 XML 并在我的代码中使用了它。对于属性标签,我使用xdt:Transform 并作为第一行的返回值Replace 非常感谢。它工作正常,实际上我想念您使用“XDocument”对象提供的解决方案。但是在使用“XmlDocument”对象时它工作正常。标记为答案。【参考方案2】:

如果您创建模型来保存数据,那么您可以使用 2 行代码轻松地从文件中反序列化对象:

public class appSettings

    [XmlElement("add")]
    public List<Item> AddItems  get; set; 


public class Item

    [XmlAttribute("key")]
    public string Key  get; set; 
    [XmlAttribute("value")]
    public string Value  get; set; 
    [XmlAttribute(Namespace="http://schemas.microsoft.com/XML-Document-Transform")]
    public string Transform  get; set; 
    [XmlAttribute(Namespace="http://schemas.microsoft.com/XML-Document-Transform")]
    public string Locator  get; set; 


XmlSerializer ser = new XmlSerializer(typeof(appSettings));
var settings = (appSettings)ser.Deserialize(File.Open("test.xml", FileMode.Open));
settings.AddItems; //<- there is your list

【讨论】:

【参考方案3】:

您是否尝试过使用XElement 类的XPathSelectElements 方法,我们可以提供xpath 来获取值

前-

doc.XPathSelectElements("//add[@xdt:Transform!=text() or not(@xdt:Transform)]", doc.Root.CreateNavigator());

我从这篇帖子中找到了这个答案from here

【讨论】:

【参考方案4】:

我想将此 XML 作为类 Key 的列表。

我在这里创建一个控制台应用程序用于演示目的。

通过以下代码,您可以将 appSettings 中的元素列表 add 从您的 xml 中获取到您的 Key 类中。

class Program
    
        static void Main(string[] args)
        
            XDocument doc = XDocument.Load(@"Your xml here");
            XNamespace ns = doc.Root.GetDefaultNamespace();
            XNamespace xdt = "http://schemas.microsoft.com/XML-Document-Transform";

            var result = doc.Descendants(ns + "appSettings")
                .Elements(ns + "add")
                         .Select(x => new Key
                         
                             Key1 = x.Attribute(xdt + "Transform") != null ? x.Attribute(xdt + "Transform").Value : "",
                             Value = x.Attribute(xdt + "Locator") != null ? x.Attribute(xdt + "Locator").Value : "",
                             Transform = x.Attribute("key") != null ? x.Attribute("key").Value : "",
                             Locator = x.Attribute("value") != null ? x.Attribute("value").Value : "",
                         ).ToList();


            result.ForEach(x => Console.WriteLine($"Transform: x.Transform, \t Locator: x.Locator, \t Key: x.Key1, \t Value: x.Value"));

            Console.ReadLine();
        
    



[Serializable]
    public class Key
    
        public string Key1  get; set; 
        public string Value  get; set; 
        public string Transform  get; set; 
        public string Locator  get; set; 
    

输出:

【讨论】:

@Chandramouli,不知何故迟到了我的答案,但可能对你有帮助:)

以上是关于使用 c# 在属性级别读取带有名称空间的 XML的主要内容,如果未能解决你的问题,请参考以下文章

C# Linq to XML 读取多个带有属性的标签

将带有命名空间和属性的 XML 转换为 C# 模型类

读取具有多个名称空间的子节点

用C#读取XML文件,怎么可以循环读取

C# WPF 附加属性 - 错误:“XML 命名空间中不存在该属性”

C# 在忽略命名空间的同时反序列化 xml