2009-10-28 4 views
7

Учитывая следующий пример XML, мы могли бы представить схему, определяющую Root как содержащую последовательность несвязанного числа вариантов между Type1 и Type2.Сохранение порядка в последовательности выбора (LINQ To XSD)

<Root> 
    <Type1 /> 
    <Type2 /> 
    <Type2 /> 
    <Type1 /> 
</Root> 

Я тестируя миграцию из инструмента Xsd.exe который, хотя и добавляет безопасности типа имеет много маленьких раздражений. Инструмент XSD в этом случае просто создает внутри Root массив типа System.Object, и вам нужно выяснить, какие типы объектов (Type1 или Type2) находятся там. Это не совсем элегантно, но, по крайней мере, вы сохраняете порядок.

Проблема заключается в том, что LINQ to XSD создает объекты, он определяет Root как имеющий два независимых списка Type1 и Type2. Это здорово, поскольку он безопасен по типу, но теперь я теряю порядок элементов. Я построил LINQ для XSD из источника на codeplex.

Используя LINQ to XSD, как я могу сохранить порядок этих элементов?

+3

Ну, вы уже представили только два варианта. Либо вы получаете слабо типизированную коллекцию, которая сохраняет заказ, либо вы получаете строго типизированную коллекцию для каждого типа. Представьте, что вы вообще не используете какой-либо XML - как бы вы написали объект с чистым кодом, который имеет единую строго типизированную коллекцию с несколькими типами в ней? –

+0

Мой вопрос заключается в том, как сохранить порядок элементов в этом сценарии, используя Linq to XSD. Я понимаю, что для коллекции смешанных типов они должны быть из System.Object (или любого другого родителя, с которым они имеют общего). Я хочу отказаться от строго типизированных объектов в этом сценарии w/Linq для XSD, чтобы сохранить порядок. Я надеялся, что есть способ заставить его сделать это. В моем случае, порядок имеет значение, поэтому я не мог использовать Linq для XSD, хотя мне бы очень хотелось, поскольку у него много преимуществ по сравнению с XSD.exe. – Philip

+6

Вы можете сделать это с наследованием. Если оба типа 1 и Type2 имеют общий базовый класс, у вас может быть IList . Теперь у вас есть один, строго типизированный список, и порядок сохраняется.При повторении через список просто проверьте тип текущего объекта. Еогеасп (BaseType эль в элементах) { если (эл ​​является Type1) ... еще если (эл ​​является Type2) ... } –

ответ

2

Как насчет создания обертки вокруг выбора? Ограничение типов, которые он получает доступ, как это:

class Choice 
{ 
    private object _value; 

    public ChoiceEnum CurrentType { get; private set; } 

    public Type1 Type1Value 
    { 
     get { return (Type1) _value; } 
     set { _value = value; CurrentType = ChoiceEnum.Type1; } 
    } 

    public Type2 Type2Value 
    { 
     get { return (Type2) _value; } 
     set { _value = value; CurrentType = ChoiceEnum.Type2; } 
    } 
} 

Это упрощенная версия, и вам придется добавить больше проверок (если _value имеет правильный типа, что текущий тип _value и т.д.).

Затем можно фильтровать с помощью LINQ:

var q1 = from v in root.Sequence 
     where v.CurrentType == ChoiceEnum.Type1 
     select v.Type1; 

Или вы можете создать методы Root, которые окутывают запросы.

+0

Хорошее предложение. Это должно работать, но диктует дизайн самого XSD, который является неудачным, а иногда и невозможным (например, стандартные отраслевые схемы). Многие схемы, с которыми мы работаем в нашей команде, хотя и созданы нами, поэтому мы сможем использовать эту технику. – Philip

1

Linq2Xsd запускает только последовательности, когда есть элемент xsd: choice.

К счастью, я смог удалить xsd: для Amazon XSD Я использую (я просто не использовал MerchantOrderID), что позволило корректно сохранить последовательность в ToString() для xml.

  <xsd:choice>        <--- removed line 
       <xsd:element ref="AmazonOrderID"/> 
       <xsd:element ref="MerchantOrderID"/> <--- removed line 
      </xsd:choice>        <--- removed line 

      <xsd:element name="ActionType" minOccurs="0" maxOccurs="1"> 
       <xsd:simpleType> 
        <xsd:restriction base="xsd:string"> 
         <xsd:enumeration value="Refund"/> 
         <xsd:enumeration value="Cancel"/> 
        </xsd:restriction> 
       </xsd:simpleType> 
      </xsd:element> 

сгенерированный код, то правильно есть это в конструкторе, сохраняющее порядок

contentModel = new SequenceContentModelEntity(
       new NamedContentModelEntity(XName.Get("AmazonOrderID", "")), 
       new NamedContentModelEntity(XName.Get("ActionType", "")), 
       new NamedContentModelEntity(XName.Get("CODCollectionMethod", "")), 
       new NamedContentModelEntity(XName.Get("AdjustedItem", ""))); 

Вы также можете быть в состоянии сделать это вручную подклассы это сам, но я не уверен, как это будет работать с выбором xsd:. Это described here, но я его не тестировал.

Смежные вопросы