2009-11-05 10 views
17

Nasze C++ aplikacja odczytuje dane konfiguracyjne z plików XML, które wyglądają mniej więcej tak:Czy mogę wymusić kolejność atrybutów XML przy użyciu schematu?

<data> 
<value id="FOO1" name="foo1" size="10" description="the foo" ... /> 
<value id="FOO2" name="foo2" size="10" description="the other foo" ... /> 
... 
<value id="FOO300" name="foo300" size="10" description="the last foo" ... /> 
</data> 

Cała konfiguracja aplikacji składają się z ~ 2500 tych plików XML (co przekłada się na ponad 1,5 mln klucz/wartość par atrybut) . Pliki XML pochodzą z wielu różnych źródeł/zespołów i są sprawdzane pod względem schematu. Jednak czasami <value/> węzły wyglądać następująco:

<value name="bar1" id="BAR1" description="the bar" size="20" ... /> 

lub to:

<value id="BAT1" description="the bat" name="bat1" size="25" ... /> 

Aby to proces szybki, używamy Expat do analizowania dokumentów XML. Expat eksponuje atrybuty w postaci tablicy - jak to:

void ExpatParser::StartElement(const XML_Char* name, const XML_Char** atts) 
{ 
// The attributes are stored in an array of XML_Char* where: 
// the nth element is the 'key' 
// the n+1 element is the value 
// the final element is NULL 
for (int i = 0; atts[i]; i += 2) 
{ 
    std::string key = atts[i]; 
    std::string value = atts[i + 1]; 
    ProcessAttribute (key, value); 
} 
} 

To stawia całą odpowiedzialność na naszej ProcessAttribute() funkcji do zapoznania się z „klucza” i zdecydować, co zrobić z wartością. Profilowanie aplikacji pokazało, że ~ 40% całkowitego czasu analizy XML zajmuje się tymi atrybutami według nazwy/ciągu znaków.

Ogólny proces może zostać przyspieszony dramatycznie, jeśli mogę zagwarantować/wymusić kolejność atrybutów (dla początkujących, bez porównań ciągów w ProcessAttribute()). Na przykład, jeżeli atrybut „id” była zawsze 1st atrybut mogliśmy sobie z nim bezpośrednio:

void ExpatParser::StartElement(const XML_Char* name, const XML_Char** atts) 
{ 
// The attributes are stored in an array of XML_Char* where: 
// the nth element is the 'key' 
// the n+1 element is the value 
// the final element is NULL 
ProcessID (atts[1]); 
ProcessName (atts[3]); 
//etc. 
} 

Według specyfikacji schematu W3C, mogę używać <xs:sequence> w schemacie XML do wyegzekwowania kolejność elementów - ale to nie wydają się działać dla atrybutów - czy może Używam go niepoprawnie:

<xs:element name="data"> 
<xs:complexType> 
    <xs:sequence> 
    <xs:element name="value" type="value_type" minOccurs="1" maxOccurs="unbounded" /> 
    </xs:sequence> 
</xs:complexType> 
</xs:element> 

<xs:complexType name="value_type"> 
<!-- This doesn't work --> 
<xs:sequence> 
    <xs:attribute name="id" type="xs:string" /> 
    <xs:attribute name="name" type="xs:string" /> 
    <xs:attribute name="description" type="xs:string" /> 
</xs:sequence> 
</xs:complexType> 

Czy istnieje sposób, aby wymusić kolejność atrybutów w dokumencie XML? Jeśli odpowiedź brzmi "nie" - czy ktoś mógłby zaproponować alternatywę, która nie przyniosłaby ogromnej kary za wydajność?

+2

Dlaczego poszedłeś z atrybutami i nie foo1 foo1 Jest to opis? Możesz określić kolejność elementów, więc dlaczego ich nie używać? – jmucchiello

+0

+1 To bardzo dobrze napisane (i interesujące) pytanie. –

Odpowiedz

30

Według specyfikacji XML,

kolejność specyfikacji atrybutu w start-tag lub pustymi elementu tagu nie jest znacząca

Można to sprawdzić w section 3.1

1

Nie sądzę, że schemat XML obsługuje to - atrybuty są po prostu zdefiniowane i ograniczone przez nazwę, np. muszą pasować do określonej nazwy - ale nie widzę sposobu, w jaki można zdefiniować zamówienie dla tych atrybutów w XSD.

Nie wiem w żaden inny sposób, aby upewnić się, że atrybuty w węźle XML występują w określonej kolejności - nie jestem pewien, czy któryś z innych mechanizmów schematów XML, takich jak Schematron lub Relax NG, obsługuje ten ...

+4

To nie jest ograniczenie schematu XML, ale samego XML. Zobacz komentarz st.stoqnov. – porges

0

Tylko zgadnij, ale czy możesz spróbować dodać use="required" do każdej specyfikacji atrybutów?

<xs:complexType name="value_type"> 
<!-- This doesn't work --> 
<xs:sequence> 
    <xs:attribute name="id" type="xs:string" use="required" /> 
    <xs:attribute name="name" type="xs:string" use="required" /> 
    <xs:attribute name="description" type="xs:string" use="required" /> 
</xs:sequence> 
</xs:complexType> 

Zastanawiam się, czy parser jest spowolniony przez umożliwienie atrybuty opcjonalne, kiedy wydaje się, atrybuty zawsze będzie tam.

Jeszcze raz, tylko zgaduję.

EDYCJA: Specyfikacja XML 1.0 mówi, że kolejność atrybutów nie jest znacząca. http://www.w3.org/TR/REC-xml/#sec-starttags

Dlatego XSD nie będzie wymuszać żadnego zamówienia.Nie oznacza to jednak, że parsery nie dają się nabrać na szybką pracę, więc zachowuję powyższą odpowiedź, o ile działa.

1

Jestem prawie pewien, że nie ma sposobu na wymuszenie kolejności atrybutu w dokumencie XML. Zakładam, że możesz nalegać na to poprzez proces biznesowy lub inne czynniki ludzkie, takie jak umowa lub inny dokument.

Co, jeśli założyłeś, że pierwszym atrybutem było "id", i przetestowałeś nazwę, aby się upewnić? Jeśli tak, użyj wartości, jeśli nie, możesz spróbować uzyskać atrybut według nazwy lub wyrzucić dokument.

Chociaż nie jest tak skuteczny, jak wywoływanie atrybutu według jego liczby porządkowej, pewna liczba razy, która nie jest równa zeru, gdy będziesz w stanie odgadnąć, że twoi dostawcy danych dostarczyli XML do specyfikacji. Przez resztę czasu możesz podjąć inne działania.

2

Odpowiedź jest nie, niestety. Jestem zszokowany twoją liczbą 40%. Trudno mi uwierzyć, że przekształcenie "foo" w ProcessFoo trwa tak długo. Czy jesteś pewien, że 40% nie uwzględnia czasu, jaki upłynął do wykonania egzekucji ProcessFoo?

Czy można uzyskać dostęp do atrybutów według nazwy za pomocą tego dodatku Expat? To jest bardziej tradycyjny sposób uzyskiwania dostępu do atrybutów. Nie mówię, że będzie szybciej, ale warto spróbować.

+2

'Expat thing' jest jednym z najszybszych analizatorów. Nie bądź zszokowany, sprzedałeś właśnie XML przez MSFT i IBM i nie jest on skalowany :-) –

+1

Gary, masz rację. Nie wyjaśniłem dokładnie, co robi funkcja ProccessAttribute(), ponieważ uważałem, że nie było tematu oryginalnego pytania ... Parsujemy te dokumenty XML podczas uruchamiania aplikacji i wyrzucamy dane elementów do bazy danych sqlite w celu późniejszego przetworzenia . Interfejs API sqlite umożliwia wiązanie parametrów według indeksu - więc jeśli mógłbym mieć pewność, że atrybuty XML były zawsze w tej samej kolejności, co parametry w instrukcji Insert, wszystko byłoby o wiele (dużo) szybsze. –

0

Z tego, co pamiętam, Expat to nie sprawdzający poprawności parser i lepszy dla niego ... więc możesz prawdopodobnie zepsuć ten pomysł XSD. Zależność od zamówienia nie jest dobrym pomysłem w wielu podejściach XML (XSD skrytykowało zamówienie na element, co jest bardzo popularne w ciągu dnia, na przykład przez pro lub anty-sprzedawców usług XML w MSFT).

Wykonaj niestandardowe kodowanie i po prostu rozszerz swoją logikę, aby uzyskać bardziej wydajne wyszukiwanie lub przekopiuj źródło do parsera. Łatwo jest napisać oprzyrządowanie do kodowania efektywnego zamiennika, jednocześnie chroniąc przed nim agenty programowe i użytkowników. Chcesz to zrobić, aby migracja była łatwa, przy jednoczesnym zachowaniu zgodności wstecznej i odwracalności. Przejdź również do więzów o stałym rozmiarze/nazwa-atrybutu-tłumaczenia.

[Uważaj się za szczęściarza z Expatem :) i jego surową szybkość. Wyobraź sobie, jak kochać deweloperów CLR obiektów skalowania XML one rutynowo wysłać 200MB na drucie w procesie „po prostu przeglądając bazę danych” ..]

6

atrybuty XML nie mieć zamówienie, dlatego nie ma celu wymuszenia .

Jeśli chcesz coś zamówić, potrzebujesz elementów XML. Lub coś innego niż XML. JSON, YAML i bEncode, np. posiadają zarówno mapy (które są nieuporządkowane), jak i sekwencje (które są uporządkowane).

4

Jak zauważyli inni, nie, nie można polegać na zamawianiu atrybutów.

Gdybym miał jakikolwiek proces obejmujący 2500 plików XML i 1,5 miliona par klucz/wartość, otrzymywałbym te dane z XML i do bardziej użytecznej postaci tak szybko, jak tylko będę mógł. Baza danych, format serializacji binarnej, cokolwiek.Nie uzyskujesz żadnej korzyści z używania XML (poza sprawdzaniem schematu). Aktualizowałbym mój sklep za każdym razem, gdy otrzymywałam nowy plik XML, i wypakowywałam 1,5 miliona elementów XML z głównego strumienia mojego procesu.

Powiązane problemy