2009-10-28 19 views
7

Biorąc pod uwagę następujący przykład XML, moglibyśmy wyobrazić sobie schemat definiujący Root jako zawierający sekwencję niezwiązanej liczby opcji między Type1 i Type2.Zachowywanie porządku w kolejności sekwencji (LINQ do XSD)

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

Przeprowadzam testowanie migracji z narzędzia XSD.exe, które jednak dodaje bezpieczeństwa typu ma wiele małych uciążliwości. Narzędzie XSD w tym przypadku tworzy wewnątrz Root tablicę typu System.Object i musisz dowiedzieć się, jakie typy obiektów (Type1 lub Type2) tam są. Nie jest całkowicie elegancka, ale przynajmniej zachowujesz porządek.

Problem polega na tym, że gdy LINQ do XSD tworzy obiekty, definiuje Root jako dwie niezależne listy typu 1 i Typ2. Jest to wspaniałe, ponieważ jest bezpieczne dla typu, ale wydaje mi się, że traci kolejność elementów. Zbudowałem LINQ do XSD ze źródła na codeplex.

Używając LINQ do XSD, w jaki sposób mogę zachować kolejność tych elementów?

+3

Cóż, już przedstawiłeś tylko dwie opcje. Albo otrzymujesz słabo wpisaną kolekcję, która zachowuje porządek, albo dostajesz silnie typowaną kolekcję według typu. Udawaj, że w ogóle nie korzystasz z żadnego XML-a - w jaki sposób napiszesz obiekt czystego kodu, który ma jedną silnie wpisaną kolekcję z wieloma typami? –

+0

Moje pytanie brzmi: jak zachować kolejność elementów w tym scenariuszu, używając Linq do XSD. Zdaję sobie sprawę, że mam zbiór typów mieszanych, które powinny być w System.Object (lub czymkolwiek innym, który mają ze sobą wspólnego). Jestem gotów zrezygnować z silnie typowanych obiektów w tym scenariuszu z Linq do XSD, aby zachować porządek. Miałem nadzieję, że istnieje sposób, aby to zmusić. W moim przypadku użycia, zamówienie ma znaczenie, więc nie mogłem używać Linq do XSD, chociaż naprawdę chciałbym, ponieważ ma wiele zalet w porównaniu z XSD.exe. – Philip

+6

Możesz to zrobić z dziedziczeniem. Jeśli oba typy Type1 i Type2 mają wspólną klasę podstawową, możesz mieć IList . Teraz masz jedną, silnie wpisaną listę, a zamówienie jest zachowane.Podczas powtarzania listy, po prostu sprawdź typ bieżącego obiektu. foreach (BaseType el w elementach) { if (el jest Type1) ... else if (el jest Type2) ... } –

Odpowiedz

2

Co powiesz na tworzenie otoki wokół wyboru? Ograniczenie typów, które ma dostęp tak:

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; } 
    } 
} 

Jest to uproszczona wersja, i trzeba będzie dodać więcej walidacji (jeżeli _value jest odpowiedniego typu, jaki jest aktualny typ _value, etc).

Następnie można filtrować je z LINQ:

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

Albo można utworzyć metody root, która będzie zawijać zapytań.

+0

Dobra sugestia. To powinno zadziałać, ale dyktuje projekt samego XSD, co jest niefortunne, a czasem niemożliwe (np. Standardowe schematy branżowe). Wiele schematów, z którymi współpracujemy w naszym zespole, zostało przez nas stworzonych, więc możemy korzystać z tej techniki. – Philip

1

Linq2Xsd pojawia się tylko w sekwencjach, gdy jest element xsd: choice.

Na szczęście udało mi się usunąć xsd: wybór dla Amazon XSD używam (po prostu nie korzystałem z MerchantOrderID), co pozwoliło poprawnie zachować sekwencję w ToString() dla 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> 

Wygenerowany kod następnie poprawnie ma to w konstruktorze, który zachowuje kolejność

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

może także być w stanie to zrobić ręcznie przez instacji go poczuć, ale jestem nie wiem, jak to by działało z xsd: choice. To jest described here, ale nie testowałem tego.