Из HTML файла взять переменные одного типа в качестве массива в C#
(C#) У меня есть некий файл, код которого по синтаксису сильно схож с HTML. Мне нужно сделать так, чтобы программа считала все значения между полями .
<dict>
<key>FRAME_ID</key>
<string>3aceeda1-482d-48ea-87fd-89a5a9e5ef1e</string>
<key>UID</key>
<string>3aceeda1-482d-48ea-87fd-89a5a9e5ef1e</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
</dict>
<dict>
<key>FRAME_ID</key>
<string>01bee6f7-1ff1-43cc-a804-eab0d2c8a2b3</string>
<key>UID</key>
<string>01bee6f7-1ff1-43cc-a804-eab0d2c8a2b3</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
</dict>
<dict>
<key>FRAME_ID</key>
<string>fd11ffe2-23c4-4325-9b35-24d2d9ab7193</string>
<key>UID</key>
<string>fd11ffe2-23c4-4325-9b35-24d2d9ab7193</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
Как это можно реализовать в C#
Ответы (1 шт):
С этими данными можно работать как с XML (да и по сути это он и есть), но увы, он у вас не полный и тут либо вы так скопировали, либо он у вас "битый".
У вас есть 3 объекта
dict, каждый такой объект должен быть закрыт в конце (</dict>).
Ваш XML не содержит в конце последнего элемента закрывающий тег.XML не позволяет хранить в себе два и более объекта верхнего уровня, а это значит, что у вас должен быть еще какой либо объект, который будет уже внутри себя содержать все
dict.
Если подправить то, что вы предоставили, то "валидный" XML будет следующий:
<SomeItems>
<dict>
<key>FRAME_ID</key>
<string>3aceeda1-482d-48ea-87fd-89a5a9e5ef1e</string>
<key>UID</key>
<string>3aceeda1-482d-48ea-87fd-89a5a9e5ef1e</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
</dict>
<dict>
<key>FRAME_ID</key>
<string>01bee6f7-1ff1-43cc-a804-eab0d2c8a2b3</string>
<key>UID</key>
<string>01bee6f7-1ff1-43cc-a804-eab0d2c8a2b3</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
</dict>
<dict>
<key>FRAME_ID</key>
<string>fd11ffe2-23c4-4325-9b35-24d2d9ab7193</string>
<key>UID</key>
<string>fd11ffe2-23c4-4325-9b35-24d2d9ab7193</string>
<key>FRAME_TYPE</key>
<integer>0</integer>
<key>DURATION</key>
<integer>1</integer>
<key>IS_FRAME_PAUSED_FOR_AUDIO</key>
<false/>
</dict>
</SomeItems>
С этим думаю разобрались.
Теперь давайте попробуем разобрать эти данные. Что мы видим тут?
- Есть строгая последовательность, где сначала идет ключ, а затем идет его значение.
- Значение в имени содержит свой тип.
Для начала разберемся с типом:
Тут отлично бы подошел подход вида
var value = Convert.ChangeType(объект, Type.GetType(его тип)))
Но увы, в c# нет например integer типа, есть Int32 и тут нам придется городить свои велосипеды, например, такие:
private static object CastTo(string value, string type)
{
switch (type)
{
case "integer":
if (int.TryParse(value, out int intRes)) return intRes;
break;
default:
if (bool.TryParse(type, out bool boolRes)) return boolRes;
break;
}
return value;
}
Пояснение:
- На вход передается методу значение и его тип.
- Если тип подходит одному из условий, то мы попытаемся конвертировать значение в него и при удаче вернуть
object. - Если тип непонятен (у вас это
<false/>), то пытаемся конвертировать вbool. - Если все наши попытки преобразовать провалились, то возвращаем
stringрезультат.
Ну теперь давайте разберем XML:
var document = XElement.Load("Test.xml");
var items = document.Descendants("dict");
var result = new List<Dictionary<string, object>>();
foreach (var item in items)
{
var dict = new Dictionary<string, object>();
for (int i = 0; i < item.Elements().Count(); i += 2)
{
var key = item.Elements().ElementAt(i).Value;
var valueElement = item.Elements().ElementAt(i + 1);
var value = CastTo(valueElement.Value, valueElement.Name.LocalName);
dict.Add(key, value);
}
result.Add(dict);
}
Поясняю:
XElement.Load("Test.xml");- загружаем файл.document.Descendants("dict");- берем из файла всеdictобъекты.foreach (var item in items)- проходимся по ним и делаем с каждым объектом:for (int i = 0; i < item.Elements().Count(); i += 2)- делаем цикл, который будет с шагом по 2, давать нам индекс до тех пор, пока кол-во элементов внутри одногоdictбудет больше, чем индекс (будем получать int значения0 2 4 6...).item.Elements().ElementAt(i).Value;- берем значение из строк вида<key>.item.Elements().ElementAt(i + 1);- берем следующий после<key>объект.CastTo(valueElement.Value, valueElement.Name.LocalName);- вызываем ранее созданный метод, который вернет нам сконвертированное значение. На вход отдаем значение внутри скобок и название (integerи др).dict.Add(key, value);- добавляем результат во временный словарь.
result.Add(dict);- добавляем временный словарь в основной "список словарей".
Собственно все, результатом будет нечто такое:
Как видим, все данные успешно загрузились и имеют соответствующий тип.
Теперь мы можем например сделать так:
var someValue = (bool)result[0]["IS_FRAME_PAUSED_FOR_AUDIO"];
