Чтение XML-элементов и соединение их в 1 переменную - PullRequest
0 голосов
/ 17 октября 2018

У меня есть 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>

Таким образом, каждый экземпляр может не содержать ни одной, ни одной, ни нескольких меток, и каждая метка содержит текст, а некоторые метки содержат текст И группу.

Итак, моя проблема: я хочу получить эти значения в одной строке для каждого экземпляра.Каждый текст должен быть разделен запятой, и каждая группа должна быть вместе с текстом, которому она принадлежит, знаком "=".Так, например, для первого экземпляра строка должна выглядеть так:

"Pass = SuccessfulCompleted, PassDistance = Medium, Player = 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());

Спасибо за помощь!

Ответы [ 3 ]

0 голосов
/ 17 октября 2018

Если я понимаю, что вы хотите!Я думаю, что вы можете использовать такой код:

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() };
        });
0 голосов
/ 17 октября 2018

Мое решение - я решил создать класс Label для сопоставления 1 отдельной метки и класс LabelGroup для сопоставления всех меток определенного элемента <instance>:

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

EDIT

Учитывая, что OP использует более старую версию .NET Framework (3.5), классы Label и LabelGroup должны быть изменены следующим образом.Остальная часть кода должна быть совместима с .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;
    }
}
0 голосов
/ 17 октября 2018

Следующий код даст вам текст для экземпляра так, как вы этого хотите.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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...