Dart / Flutter에서 거대한 (3Gb) XML 파싱
거대한 XML 파일을받는 사이트가 있습니다. Dart에서 2 개의 클래스로 파싱해야합니다.
XML (일부) :
<fb-updates xmlns:l="https://www.w3.org/1999/xlink" timestamp="2018-04-19 11:33:14">
<updated-book id="32498526" created="2018-04-18 16:35:49" last_release="2018-04-18 16:35:49" updated="2018-04-18 16:35:49" valid_till="2018-12-31" valid_from="2013-01-01" size="579411" sent_by_name="[email protected]" sent_by_id="9351951" must_import="0" options="0" price="0.90" you_can_sell="0" allow_read="0" allow_sell="0" has_trial="0" allow_full_free="0" public_domain="0" show_card="0" contract_author="9339265" contract_title="АСТ" subject_id="44580" external_id="b4854f32-430a-11e8-9a05-0cc47a52085c" cover="jpg" type="0" adult="16" file_parts="6" available="-1" available_date="2018-04-18 16:18:02" copyright_read_online="1" contract_ends="2018-12-31" udk="821.111-312.4" art_cover="jpg" lvl="2" sell_open="0" can_preorder="0" litex="1" chars="46369" images="1" drm="0" publisher="АСТ" date_written_s="1969" date_written_d="1969-01-01" lang="ru" src_lang="en" cover_h="1960" cover_w="1400" art_cover_w="1400" art_cover_h="1960" lang3="rus" src_lang3="eng" status="approved" rating="6030" url="" inapp_price="0.90">
<files>
<file size="579409" type="fb2.zip"/>
<file size="51846" type="html"/>
<file size="583471" type="html.zip"/>
<file size="47604" type="txt"/>
<file size="20832" type="txt.zip"/>
<file size="623059" type="rtf.zip"/>
<file size="663336" type="a4.pdf"/>
<file size="708752" type="a6.pdf"/>
<file size="447161" type="mobi.prc"/>
<file size="1474324" type="epub"/>
<file size="590189" type="ios.epub"/>
<file size="578047" type="fb3"/>
</files>
<book-title title="Наследство Боксдейла"/>
<annotation>
<p>
«– Видишь ли, мой дорогой Адам, – мягко объяснял каноник, прохаживаясь с главным суперинтендентом Дэлглишем под вязами возле своего пасторского дома, – как бы нам ни было кстати это наследство, оно не принесет мне радости, если моя приемная бабушка Элли получила в свое время эти деньги недостойным способом.
</p>
<p>
Каноник имел в виду, что они с женой не смогут воспользоваться пятьюдесятью тысячами фунтов, оставленными им его приемной бабушкой Элли, если шестьдесят семь лет назад она отравила своего престарелого мужа мышьяком, чтобы получить их. Поскольку в 1902 году это обвинение было снято с тетушки Элли судом, который, по мнению ее хемпширских соседей, в качестве публичного зрелища мог состязаться с церемонией коронации, щепетильность каноника казалась не совсем уместной…»
</p>
</annotation>
<authors>
<author id="dc3b5610-2a80-102a-9ae1-2dfe723fe7c7">
<subject_id>44580</subject_id>
<url>fillis-dzheyms/</url>
<first-name>Филлис Дороти</first-name>
<middle-name/>
<last-name>Джеймс</last-name>
<full-name-rodit>Филлис Дороти Джеймс</full-name-rodit>
<lvl>2</lvl>
<relation>0</relation>
</author>
<author id="e4f1d9b0-2a80-102a-9ae1-2dfe723fe7c7">
<subject_id>44696</subject_id>
<url>i-doronina/</url>
<first-name>Ирина</first-name>
<middle-name>Яковлевна</middle-name>
<last-name>Доронина</last-name>
<full-name-rodit>Ирины Дорониной</full-name-rodit>
<lvl>1</lvl>
<relation>1</relation>
</author>
<author id="c9a05514-1ce6-11e2-86b3-b737ee03444a">
<subject_id>2835185</subject_id>
<url>raznoe-4/</url>
<first-name>Литагент</first-name>
<middle-name/>
<last-name>АСТ</last-name>
<full-name-rodit/>
<lvl>2</lvl>
<relation>2</relation>
</author>
</authors>
<genres>
<genre title="зарубежные детективы" id="5219" bisac="FIC022000" master="1"/>
<genre title="классические детективы" id="5261" bisac="FIC022000"/>
</genres>
<relations>
<related uuid="BA8F3184-9049-4EAF-A47B-9D711D9135DC" relation="6" type="0"/>
</relations>
<copyrights>
<copyright id="9339265" title="АСТ" percent="100.00"/>
</copyrights>
<livelib livelib_id="1001260109" rating="7.263" avg_mark="3.8246" count_readers="2271" widget_url="book/1100906/ratingbutton2015.png" widget_url2="book/1100906/ratingbuttonwhite.png" mark_1="2" mark_2="5" mark_3="48" mark_4="78" mark_5="885"/>
</updated-book>
<updated-book id="32523047" created="2018-04-19 09:14:23" last_release="2018-04-19 09:14:23" updated="2018-04-19 09:14:23" valid_till="2021-11-01" valid_from="2016-11-01" size="5653231" sent_by_name="sabanova" sent_by_id="9355626" must_import="0" options="68" price="5.99" you_can_sell="0" allow_read="0" allow_sell="0" has_trial="0" allow_full_free="0" public_domain="0" show_card="64" contract_author="9356032" contract_title="Эксмо" subject_id="44790" external_id="0a6e477f-4398-11e8-aa6b-0cc47a520474" cover="jpg" type="1" adult="0" file_parts="0" available="-1" available_date="2018-04-19 09:11:16" copyright_read_online="0" contract_ends="2021-02-12" art_cover="jpg" lvl="4" sell_open="0" can_preorder="0" litex="0" chars="4368" drm="0" publisher="" lang="ru" cover_h="1500" cover_w="1071" art_cover_w="1071" art_cover_h="1500" lang3="rus" status="approved" url="" inapp_price="5.99">
<files>
<group value="Ознакомительный фрагмент. MP3" group_id="1">
<file id="37754271" size="5653231" filename="Sample.mp3" seconds="4368" mime_type="audio/mpeg" file_description="MP3"/>
</group>
<group value="Стандартное качество. MP3" group_id="5">
<file id="37754255" size="5669432" filename="01.mp3" seconds="354" mime_type="audio/mpeg" file_description="MP3"/>
<file id="37754231" size="14099251" filename="02.mp3" seconds="880" mime_type="audio/mpeg" file_description="MP3"/>
<file id="37754263" size="11474467" filename="03.mp3" seconds="716" mime_type="audio/mpeg" file_description="MP3"/>
<file id="37754215" size="5472573" filename="04.mp3" seconds="341" mime_type="audio/mpeg" file_description="MP3"/>
<file id="37754239" size="24781451" filename="05.mp3" seconds="1548" mime_type="audio/mpeg" file_description="MP3"/>
<file id="37754247" size="8470594" filename="06.mp3" seconds="529" mime_type="audio/mpeg" file_description="MP3"/>
</group>
<group value="Мобильная версия. MP4" group_id="19">
<file id="37754223" size="31707503" filename="Sovetnik_Po_Kulture.m4b" seconds="4366" mime_type="audio/m4b" file_description="M4B-файл"/>
</group>
</files>
<book-title title="Советник по культуре"/>
<annotation>
<p>
Николай Стверцов прибыл на планету Ниона в качестве советника по культуре посольства Земной Федерации. Он должен сыграть важную роль в межгалактическом проекте «Восхождение». Проект призван помочь пяти расам Нионы достичь более высокого уровня развития. Но, узнав о страшной тайне изготовления шейота, который является главным предметом экспорта с отсталой планеты, Стверцов начинает сомневаться в правильности политики Земной Федерации на Нионе…
</p>
</annotation>
<authors>
<author id="ea92d3b4-2a80-102a-9ae1-2dfe723fe7c7">
<subject_id>44790</subject_id>
<url>aleksey-kalugin/</url>
<first-name>Алексей</first-name>
<middle-name>Александрович</middle-name>
<last-name>Калугин</last-name>
<full-name-rodit>Алексея Калугина</full-name-rodit>
<lvl>4</lvl>
<relation>0</relation>
<exid>1-00000025829</exid>
</author>
<author id="556f2637-8bde-11e6-9c73-0cc47a1952f2">
<subject_id>10117645</subject_id>
<url>audioagent-litres-chtec-pablik/</url>
<first-name>Аудиоагент</first-name>
<middle-name/>
<last-name>ЛитРес Чтец</last-name>
<full-name-rodit>Аудиоагента ЛитРес Чтец</full-name-rodit>
<lvl>1</lvl>
<relation>2</relation>
</author>
<author id="a4d115a3-a4f2-11e6-a11d-0cc47a5203ba">
<subject_id>10389074</subject_id>
<url>raznoe-10389074/</url>
<first-name>Аудиоагент</first-name>
<middle-name/>
<last-name>1 редакция-прямой договор</last-name>
<full-name-rodit/>
<lvl>1</lvl>
<relation>2</relation>
</author>
<author id="f703f2a3-24cc-11e7-b088-0cc47a52085c">
<subject_id>11119920</subject_id>
<url>dumanskiy-andrey/</url>
<first-name>Андрей</first-name>
<middle-name/>
<last-name>Думанский</last-name>
<full-name-rodit>Думанского Андрея</full-name-rodit>
<lvl>1</lvl>
<relation>2</relation>
</author>
<author id="f703f2a3-24cc-11e7-b088-0cc47a52085c">
<subject_id>11119920</subject_id>
<url>dumanskiy-andrey/</url>
<first-name>Андрей</first-name>
<middle-name/>
<last-name>Думанский</last-name>
<full-name-rodit>Думанского Андрея</full-name-rodit>
<lvl>1</lvl>
<relation>6</relation>
</author>
</authors>
<genres>
<genre title="научная фантастика" id="5073" bisac="FIC028020"/>
<genre title="социальная фантастика" id="5078" bisac="FIC028000"/>
</genres>
<relations>
<related uuid="76316fbc-2c44-102b-839c-b3fddb510218" relation="8" type="0"/>
</relations>
<copyrights>
<copyright id="9354189" title="ЛитРес: чтец" percent="26.00"/>
<copyright id="9354794" title="Эксмо" percent="50.00"/>
<copyright id="9356032" title="Думанский Андрей" percent="100.00"/>
</copyrights>
</updated-book>
<removed-book id="24261892" uid="fc3ba230-4753-11e7-b2fb-0cc47a52085c" removed="2018-04-19 10:34:13"/>
</fb-updates>
따라서 구현할 클래스가 2 개 있습니다. 하나는 업데이트 된 책용이고 다른 하나는 제거 된 책용입니다.
수업은 다음과 같습니다.
RemovedBook은 간단합니다.
class RemovedBook {
RemovedBook({
this.id,
this.uid,
this.removed,
});
String id;
String uid;
DateTime removed;
}
UpdatedBook 클래스는 더 복잡하지만 질문의 범위는 아닙니다.
문제는 Dart Xml 패키지로 XML 응답을 어떻게 구문 분석 할 수 있는지입니다.
스트림 기능에 대한 설명이 있지만 클래스를 얻는 방법을 알 수 없습니다.
final url = Uri.parse('http://ip-api.com/xml/');
final request = await httpClient.getUrl(url);
final response = await request.close();
final stream = response
.transform(utf8.decoder)
.transform(const XmlEventDecoder())
.transform(const XmlNormalizer())
.expand((events) => events)
.forEach((event) => print(event));
그렇다면 스트림에서 수업을 어떻게받을 수 있습니까?
답변
Flutter의 HttpClient 스트림에서 XML 요소를 그룹화하는 방법 의 답변 은 이벤트 스트림 ( skipWhile
및 의 조건에 의해 제한됨 takeWhile
)을 노드의 하위 트리 (사용 XmlNodeDecoder
) 로 변환하는 방법을 설명합니다 .
이 경우 좀 더 복잡합니다. 건너 뛰기 / 부분을 여러 번 입력 / 종료해야합니다. 불행히도 나는 Dart Streams로 우아한 방식으로 그것을 수행하는 방법을 알지 못합니다 (일부 Rx 확장을 사용하면 더 쉬울 수 있습니까?). 그러나 xml 4.4.0부터 다음 과 같이 작성할 수 있습니다.
response
.transform(utf8.decoder)
.toXmlEvents()
.selectSubtreeEvents((event) =>
event.name == 'updated-book' || event.name == 'removed-book')
.toXmlNodes()
.flatten()
.where((node) => node is XmlElement)
.cast<XmlElement>()
.map((element) {
if (element.name.qualified == 'removed-book') {
return RemovedBook(
id: element.getAttribute('id'),
...
));
} else {
...
}
})
.forEach(print);
Flutter를 사용하여 모바일 장치에서 이러한 데이터를 읽고 처리하는 것이 확실히 가능하지만, 사전에 더 강력한 장치에서 그러한 많은 양의 데이터를 사전 처리하는 것을 고려할 수 있습니다.