2017-02-14 24 views
1

Я работаю с SVG-файлами в Xamarin.Forms. Эти файлы будут очень простыми, содержащими одну форму, где эта форма обычно будет polyline. Тем не менее, есть краевые случаи, когда может быть одна из нескольких других точечных форм. При анализе этих файлов я пытаюсь захватить значение определенного атрибута элемента shape.Как получить значение атрибута из XDocument, когда требуемое имя XElement неизвестно до выполнения?

Вот пример того, что я ожидаю, чтобы синтаксический анализ:

<svg width="1200" height="800" version="1.1" bordercolor="#666666" borderopacity="1.0" xmlns="http://www.w3.org/2000/svg"> 
    <polyline stroke="#004976" fill="transparent" stroke-width="5" points="479,91 ..." /> 
</svg> 

Так что в этом наиболее общем случае я пытаюсь получить значение атрибута points для polyline. Я уверен, что это будет простая функция LINQ-to-XML, но я пропущу ее. Вот что я пытался до сих пор:

public static Point[] GetPointsFromSVG(XDocument svg) 
{ 
    XElement shape = svg.Descendants().First(); 
    string pointsValue = shape.Attribute("points").Value; 

    var points = pointsValue.Split(' ').Select(x => x.Split(',')) 
          .Select(y => new Point(int.Parse(y[0]), int.Parse(y[1]))) 
          .ToArray(); 

    return points; 
} 

Я попробовал несколько версий, но в каждом случае shape является null даже если XDocument объект является действительным и правильно отформатирован. Также обратите внимание, что я не женат на этом подходе, мне просто нужно что-то, что работает!

ответ

2

Если вы ждете именно 1 «указывает» атрибут, то вы можете просто поиск всех потомков для этого имени:

var xmlString = @"<svg width=""1200"" height=""800"" version=""1.1"" bordercolor=""#666666"" borderopacity=""1.0"" xmlns=""http://www.w3.org/2000/svg""> 
    <polyline stroke=""#004976"" fill=""transparent"" stroke-width=""5"" points=""479,91 ..."" /> 
</svg>"; 

var pointsValue = XDocument.Parse(xmlString) 
    .Descendants() 
    .Attributes("points") 
    .Single() 
    .Value; 

Где Single() сгенерирует исключение, если есть ноль или более одного элемента в коллекции , Или вы можете удалить .Single() и foreach через все результаты .Descendants().Attributes("points").

1

Вам просто не хватает одной вещи - когда вы делаете svg.Descendants().First(), это дает вам первый потомок документа, который является элементом svg.

Вместо этого сделайте svg.Root.Descendants().First(), или даже просто svg.Root.FirstNode as XElement.

string svgString = @"<svg width='1200' height='800' version='1.1' bordercolor='#666666' borderopacity='1.0' xmlns='http://www.w3.org/2000/svg'> 
    <polyline stroke='#004976' fill='transparent' stroke-width='5' points='479,91 ...' /> 
</svg>"; 
var svg = XDocument.Parse(svgString); 
XElement shape = svg?.Root?.FirstNode as XElement; 

if (shape == null) return null; 

string pointsValue = shape.Attribute("points").Value; 

var points = pointsValue.Split(' ').Select(x => x.Split(',')) 
         .Select(y => new Point(int.Parse(y[0]), int.Parse(y[1]))) 
         .ToArray(); 


Console.ReadKey(); 

Сразу отметим, что это будет не совсем работа becauase из «...» в атрибуте SVG, который будет вызывать исключение .... Кроме того, обратите внимание, что ваши ценности вполне могли бы в конечном итоге десятичные/Парный/поплавки, не Интс (например points='479.994,91.2223 ....'

+0

Спасибо за информацию, я попробую! Также спасибо за указание вопроса «int.Parse», я полностью забыл об этом. «...» - это всего лишь мой способ усечения списка точек. –

+1

Да, я понимаю это о '...', просто понимаю, что существуют допустимые значения, отличные от int, но без проблем. Если это помогло, подумайте о том, чтобы выставить/обозначить его как правильный ответ. –