【问题标题】:Reading XML Elements and connect them in 1 variable读取 XML 元素并将它们连接到 1 个变量中
【发布时间】:2018-10-17 12:20:49
【问题描述】:

我有一个如下所示的 XML 文件:

<instance>
    <ID>2</ID>
    <start>213.5000000000</start>
    <end>231.3900001049</end>
    <code>Away Pass</code>
    <label>
        <group>Pass</group>
        <text>SuccessfullyCompleted</text>
    </label>
    <label>
        <group>PassDistance</group>
        <text>Medium</text>
    </label>
    <label>
        <group>Player</group>
        <text>John Doe</text>
    </label>
</instance>
<instance>
    <ID>3</ID>
    <start>214.0000000000</start>
    <end>225.0000000000</end>
    <code>Kickoff</code>
    <label>
        <text>Pass</text>
    </label>
</instance>
<instance>
    <ID>4</ID>
    <start>215.0000000000</start>
    <end>226.0000000000</end>
    <code>ShotOnGoal</code>
</instance>

所以每个实例可以不包含一个或多个标签,每个标签都包含一个文本,而一些标签包含一个文本和一个组。

所以我的问题是:我想为每个实例在一个字符串中获取这些值。每个文本应该用逗号分隔,每个组应该与它所属的文本一起用一个“=”。因此,例如对于第一个例子,字符串应该看起来像

“通过 = 成功完成,通过距离 = 中等,玩家 = John Doe”

我真的不知道如何实现这一点,因此我的代码在我阅读彼此分开的组和文本时看起来像这样:

var labelsGroupsTmp = from label in instance.Elements("label") select label.Element("group").Value;
string labelsGroups = string.Join(",", labelsGroupsTmp.ToArray());
var labelsTextTmp = from label in instance.Elements("label") select label.Element("text").Value;
string labelsText = string.Join(",", labelsTextTmp.ToArray());

感谢您的帮助!

【问题讨论】:

  • Id=3 的实例没有组元素,该特定情况的结果应该是什么样的?
  • 另外,第三个实例呢?没有标签,所以应该忽略该特定实例吗?
  • @RuiJarimba 如果没有像实例 2 (ID=3) 这样的组,我只想拥有文本。如果在实例 3 (ID=4) 中根本没有标签,则它应该为空/忽略
  • 根据您的反馈修正了我的答案。顺便说一句,您使用的是哪个 .NET 版本?
  • @RuiJarimba 我不太确定,因为我正在统一使用它(版本 2018.2.2f1)。我不知道在哪里可以弄清楚那里使用的是哪个版本的 .NET,但我认为它应该是 3.5 版

标签: c# .net xml string unity3d


【解决方案1】:

如果我明白你想要什么!我认为您可以使用这样的代码:

var txt = $"<root>{text}</root>";
var xml = XDocument.Parse(txt);
var elems = xml.XPathSelectElements("//instance").Select(
    x =>
        {
            var sb = new StringBuilder();
            foreach (var le in x.Elements("label"))
            {
                sb.Append(", ");
                sb.Append(le.Element("group") == null ? string.Empty : le.Element("group")?.Value + "=");
                sb.Append(le.Element("text") == null ? string.Empty : le.Element("text")?.Value);
            }

            if (sb.Length > 0)
            {
                sb.Remove(0, 2);
            }

            return new { Instance = x, LabelString = sb.ToString() };
        });

【讨论】:

    【解决方案2】:

    我的解决方案 - 我决定创建一个 Label 类来映射 1 个单个标签和一个 LabelGroup 类来映射特定 &lt;instance&gt; 元素的所有标签:

    public class Label
    {
        public string Group { get; set; }
        public string Text { get; set; }
    
        public override string ToString()
        {
            if (string.IsNullOrEmpty(Group))
            {
                return Text ?? string.Empty;
            }
    
            return $"{Group ?? string.Empty} = {Text ?? string.Empty}";
        }
    }
    
    public class LabelGroup
    {
        private readonly List<Label> _labels;
    
        public LabelGroup(List<Label> labels)
        {
            _labels = labels ?? throw new ArgumentNullException(nameof(labels));
        }
    
        /// <inheritdoc />
        public override string ToString()
        {
            if (_labels.Any())
            {
                return string.Join(", ", _labels);
            }
    
            return string.Empty;
        }
    }
    

    然后使用一些 Linq 来获取数据:

    string xml = "...."; // xml goes here
    
    var groups = from instance in XDocument.Parse($"<root>{xml}</root>").Descendants("instance")
                 let labels = instance.Descendants("label")
                 where labels.Any() // ignore <instance> without <label> elements
                 let labelList = CreateLabels(labels)
                 select new LabelGroup(labelList);
    
    
    foreach (var labelGroup in groups)
    {
        Console.WriteLine(labelGroup);
    }
    

    CreateLabels 方法:

    private static List<Label> CreateLabels(IEnumerable<XElement> elements)
    {
        List<Label> labels = elements.Select(x => new Label {
            Group = x.Element("group")?.Value,
            Text = x.Element("text")?.Value
        }).ToList();
    
        return labels;
    }
    

    请注意,您需要将 XML 包装在一个虚拟元素中以避免错误 System.Xml.XmlException: 'There are multiple root elements. Line 19, position 2.',如下所示:

    XDocument.Parse($"<root>{xml}</root>")
    

    编辑

    鉴于 OP 使用的是旧版本的 .NET Framework (3.5),LabelLabelGroup 类应更改如下。其余代码应与 .NET 3.5 兼容:

    public class Label
    {
        public string Group { get; set; }
        public string Text { get; set; }
    
        public override string ToString()
        {
            if (string.IsNullOrEmpty(Group))
            {
                return Text;
            }
    
            return string.Format("{0} = {1}", Group ?? string.Empty, Text ?? string.Empty);
        }
    }
    
    public class LabelGroup
    {
        private readonly List<Label> _labels;
    
        public LabelGroup(List<Label> labels)
        {
            if (labels == null)
            {
                throw new ArgumentNullException("labels");
            }
    
            _labels = labels;
        }
    
        public override string ToString()
        {
            if (_labels.Any())
            {
                return string.Join(", ", _labels.Select(x => x.ToString()).ToArray());
            }
    
            return string.Empty;
        }
    }
    

    【讨论】:

      【解决方案3】:

      以下代码将为您提供所需的实例文本。 xml 是包含给定 XML 的字符串,但您必须将其包含在具有任意名称的环绕标记中,在下面的代码中, 才有效,因为您的示例包含多个根元素。

      var str = XElement.Parse(@"<s>
        <instance>...</instance>
        <instance>...</instance>
        <instance>...</instance>
      </s>");
      var emptyGroup = new XElement("group");
      foreach (var instance in str.Elements("instance"))
      {
        var labels = from label in instance.Elements("label")
          select string.Format("{0}{1}{2}", 
            label.Element("group") == null ? "" : label.Element("group").Value, 
            string.IsNullOrWhiteSpace((label.Element("group") ?? emptyGroup).Value) ? "" : "=",
            label.Element("text").Value);
        string s = string.Join(", ", labels);
        // do whatever s is needed for
      }
      

      【讨论】:

      • 您需要声明变量实例,否则您的代码示例甚至无法编译。
      • 我尝试运行您的代码但出现异常:System.Xml.XmlException: 'There are multiple root elements. Line 19, position 2.'
      • 您的代码对我有用。谢谢。唯一的问题是我必须使用“IsNullOrEmpty”而不是“IsNullOrWhiteSpace”,因为我在 Unity 中运行它并且它说没有 IsNullOrWhiteSpace 的定义。
      • IsNullOrWhiteSpace 是在 .Net 4 中引入的,我相信,也许您使用的是旧版本的框架。
      • @RuiJarimba,给定的 xml 必须包含在另一个任意标签中,如我的回答中所述。遇到和你以前一样的错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      • 2015-06-29
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 1970-01-01
      • 2017-11-12
      相关资源
      最近更新 更多