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ść?
Dlaczego poszedłeś z atrybutami i nie foo1 foo1 Jest to opis description> ? Możesz określić kolejność elementów, więc dlaczego ich nie używać? –
jmucchiello
+1 To bardzo dobrze napisane (i interesujące) pytanie. –