1use roxmltree::{Node, Document};
43use super::super::errors::{Error};
44
45
46#[derive(Debug, PartialEq)]
47pub struct Reference {
48 pub citation: Option<String>,
49 pub article_id_list: ArticleIdList
50}
51
52#[derive(Debug, PartialEq)]
53pub struct ArticleId {
54 pub id_type: Option<String>,
55 pub id: Option<String>
56}
57
58#[derive(Debug, PartialEq)]
59pub struct ArticleIdList {
60 pub article_ids: Vec<ArticleId>
61}
62
63#[derive(Debug, PartialEq)]
64pub struct ReferenceList {
65 pub references: Vec<Reference>
66}
67
68#[derive(Debug, PartialEq)]
69pub struct PubmedData {
70 pub publication_status: Option<String>,
71 pub article_id_list: Option<ArticleIdList>,
72 pub reference_list: Option<ReferenceList>,
73 pub history: Vec<PubMedPubDate>
74}
75
76#[derive(Debug, PartialEq)]
77pub struct PubMedPubDate {
78 pub pub_status: Option<String>,
79 pub year: Option<String>,
80 pub month: Option<String>,
81 pub day: Option<String>
82}
83
84#[derive(Debug, PartialEq)]
86pub struct PMID {
87 pub version: Option<String>,
88 pub value: Option<String>
89}
90
91#[derive(Debug, PartialEq)]
92pub struct ISSN {
93 pub issn_type: Option<String>,
94 pub value: Option<String>
95}
96
97#[derive(Debug, PartialEq)]
98pub struct PubDate {
99 pub year: Option<String>,
100 pub month: Option<String>,
101 pub day: Option<String>
102}
103
104#[derive(Debug, PartialEq)]
105pub struct JournalIssue {
106 pub cited_medium: Option<String>,
107 pub volume: Option<String>,
108 pub issue: Option<String>,
109 pub pub_date: Option<PubDate>
110}
111
112#[derive(Debug, PartialEq)]
113pub struct Journal {
114 pub issn: Option<ISSN>,
115 pub journal_issue: Option<JournalIssue>,
116 pub title: Option<String>,
117 pub iso_abbr: Option<String>
118}
119
120#[derive(Debug, PartialEq)]
121pub struct ELocationID {
122 pub eid_type: Option<String>,
123 pub valid_yn: Option<String>,
124 pub value: Option<String>
125}
126
127#[derive(Debug, PartialEq)]
128pub struct AbstractText {
129 pub label: Option<String>,
130 pub nlm_category: Option<String>,
131 pub value: Option<String>
132}
133
134#[derive(Debug, PartialEq)]
135pub struct Abstract {
136 pub text: Vec<AbstractText>
137}
138
139#[derive(Debug, PartialEq)]
140pub struct Article {
141 pub pub_model: Option<String>,
142 pub title: Option<String>,
143 pub journal: Option<Journal>,
144 pub elocation_id: Option<ELocationID>,
145 pub language: Option<String>,
146 pub abstract_text: Option<Abstract>
147}
148
149#[derive(Debug, PartialEq)]
150pub struct MedlineJournalInfo {
151 pub country: Option<String>,
152 pub medline_ta: Option<String>,
153 pub nlm_unique_id: Option<String>,
154 pub issn_linking: Option<String>
155}
156
157#[derive(Debug, PartialEq)]
158pub struct MedlineCitation {
159 pub status: Option<String>,
160 pub owner: Option<String>,
161 pub pmid: Option<PMID>,
162 pub date_revised: Option<PubDate>,
163 pub article: Option<Article>,
164 pub medline_journal_info: Option<MedlineJournalInfo>
165}
166
167#[derive(Debug, PartialEq)]
168pub struct PubmedArticle {
169 pub medline_citation: Option<MedlineCitation>,
170 pub pubmed_data: Option<PubmedData>
171}
172
173#[derive(Debug, PartialEq)]
174pub struct PubmedArticleSet {
175 pub articles: Vec<PubmedArticle>
176}
177
178pub trait FromXMLNode {
179 fn from_node(node: &Node) -> Self;
180}
181
182impl FromXMLNode for ArticleIdList {
184 fn from_node(node: &Node) -> Self {
185 let mut article_id_list = ArticleIdList {
186 article_ids: Vec::new()
187 };
188
189 for elem in node
190 .children()
191 .filter(|n| n.is_element()) {
192
193 article_id_list
194 .article_ids
195 .push(
196 ArticleId::from_node(&elem)
197 )
198
199
200 }
201
202 article_id_list
203 }
204}
205impl FromXMLNode for ArticleId {
206 fn from_node(node:&Node) -> Self {
207 ArticleId {
208 id_type: node.attribute("IdType").map(|n| n.to_string()),
209 id: node.text().map(|n| n.to_string())
210
211 }
212 }
213}
214impl FromXMLNode for Reference {
215 fn from_node(node: &Node) -> Self {
216 let mut reference = Reference {
217 citation: None,
218 article_id_list: ArticleIdList {
219 article_ids: Vec::new()
220 }
221 };
222
223 for elem in node.children().filter(|x| x.is_element()) {
224 match elem.tag_name().name() {
225 "Citation" => reference.citation = elem.text().map(|x| x.to_string()),
226 "ArticleIdList" => reference.article_id_list = ArticleIdList::from_node(&elem),
227 _ => ()
228 }
229 }
230 reference
231 }
232}
233impl FromXMLNode for ReferenceList {
234 fn from_node(node: &Node) -> Self {
235 let mut referene_list = ReferenceList {
236 references: Vec::new()
237 };
238
239 for elem in node
240 .children()
241 .filter(|n| n.is_element()) {
242 referene_list.references.push(
243 Reference::from_node(&elem)
244 )
245 }
246
247 referene_list
248 }
249}
250impl FromXMLNode for PubMedPubDate {
251 fn from_node(node: &Node) -> Self {
252 let mut pubmed_pub_date = PubMedPubDate {
253 pub_status: node.attribute("PubStatus")
254 .map(|s| s.to_string()),
255 year: None,
256 month: None,
257 day: None
258 };
259
260 for elem in node
261 .children()
262 .filter(|e| e.is_element()){
263 match elem.tag_name().name() {
264 "Year" => pubmed_pub_date.year = elem.text().map(|e| e.to_string()),
265 "Month" => pubmed_pub_date.month = elem.text().map(|e| e.to_string()),
266 "Day" => pubmed_pub_date.day = elem.text().map(|e| e.to_string()),
267 _ => ()
268 }
269 }
270 pubmed_pub_date
271 }
272}
273impl FromXMLNode for PubmedData {
274 fn from_node(node: &Node) -> Self {
275 let mut pubmed_data = PubmedData {
276 publication_status: None,
277 article_id_list: None,
278 reference_list: None,
279 history: Vec::new()
280 };
281
282 for elem in node
283 .children()
284 .filter(|n| n.is_element()) {
285
286 match elem.tag_name().name() {
287 "PublicationStatus" => pubmed_data.publication_status = elem.text().map(|e| e.to_string()),
288 "ArticleIdList" => pubmed_data.article_id_list = Some(ArticleIdList::from_node(&elem)),
289 "ReferenceList" => pubmed_data.reference_list = Some(ReferenceList::from_node(&elem)),
290 "History" => {
291 for pub_date in elem.children().filter(|e| e.is_element()) {
292 pubmed_data.history.push(
293 PubMedPubDate::from_node(&pub_date)
294 )
295 }
296 }
297 _ => ()
298
299 }
300
301 }
302
303 pubmed_data
304 }
305}
306
307impl FromXMLNode for PMID {
309 fn from_node(node: &Node) -> Self {
310 PMID {
311 version: node.attribute("Version")
312 .map(|s| s.to_string()),
313
314 value: node.text().map(|s| s.to_string())
315 }
316 }
317}
318impl FromXMLNode for PubDate {
319 fn from_node(node: &Node) -> Self {
320 let mut date = PubDate {
321 year: None,
322 month: None,
323 day: None
324 };
325
326 for elem in node
327 .children()
328 .filter(|e| e.is_element()) {
329
330 match elem.tag_name().name() {
331 "Year" => date.year = elem.text().map(|s| s.to_string()),
332 "Month" => date.month = elem.text().map(|s| s.to_string()),
333 "Day" => date.day = elem.text().map(|s| s.to_string()),
334 _ => ()
335 }
336 }
337
338 date
339
340 }
341}
342impl FromXMLNode for ISSN {
343 fn from_node(node: &Node) -> Self {
344 ISSN {
345 issn_type: node.attribute("IssnType")
346 .map(|n| n.to_string()),
347 value: node.text()
348 .map(|t| t.to_string())
349 }
350 }
351}
352impl FromXMLNode for JournalIssue {
353 fn from_node(node: &Node) -> Self {
354 let mut journal_issue = JournalIssue {
355 cited_medium: node.attribute("CitedMedium")
356 .map(|e| e.to_string()),
357 volume: None,
358 issue: None,
359 pub_date: None
360 };
361 for elem in node
362 .children()
363 .filter(|n| n.is_element()) {
364
365 match elem.tag_name().name() {
366 "Volume" => {
367 journal_issue.volume = elem.text().map(|e| e.to_string())
368 },
369 "Issue" => {
370 journal_issue.issue = elem.text().map(|e| e.to_string())
371 },
372 "PubDate" => {
373 journal_issue.pub_date = Some(PubDate::from_node(&elem))
374 }
375 _ => ()
376 }
377 }
378 journal_issue
379 }
380}
381impl FromXMLNode for Journal {
382 fn from_node(node: &Node) -> Self {
383 let mut journal = Journal {
384 issn: None,
385 journal_issue: None,
386 title: None,
387 iso_abbr: None
388 };
389
390 for elem in node
391 .children()
392 .filter(|e| e.is_element()) {
393 match elem.tag_name().name() {
394 "ISSN" => {
395 journal.issn = Some(ISSN::from_node(&elem))
396 },
397 "JournalIssue" => {
398 journal.journal_issue = Some(JournalIssue::from_node(&elem))
399 },
400 "Title" => {
401 journal.title = elem.text()
402 .map(|e| e.to_string())
403 },
404 "ISOAbbreviation" => {
405 journal.iso_abbr = elem.text()
406 .map(|e| e.to_string())
407 },
408 _ => ()
409 }
410 }
411
412 journal
413 }
414}
415impl FromXMLNode for ELocationID {
416 fn from_node(node: &Node) -> Self {
417 ELocationID {
418 eid_type: node.attribute("EIdType")
419 .map(|e| e.to_string()),
420 valid_yn: node.attribute("ValidYN")
421 .map(|e| e.to_string()),
422 value: node.text().map(|t|t.to_string())
423 }
424 }
425}
426impl FromXMLNode for AbstractText {
427 fn from_node(node: &Node) -> Self {
428 let mut abstract_text = AbstractText {
429 label: node.attribute("Label")
430 .map(|e| e.to_string()),
431 nlm_category: node.attribute("NlmCategory")
432 .map(|e| e.to_string()),
433 value: None
434 };
435
436 let mut txt = Vec::new();
437 for elem in node
438 .children() {
439
440 if elem.is_text() {
441 match elem.text() {
442 Some(t) => txt.push(t),
443 None => ()
444 }
445
446 }
447
448 if elem.is_element() {
449 &txt.push("<");
450 if elem.namespaces().len() > 0 {
451 for ns in elem.namespaces() {
452 txt.push(ns.name().unwrap());
453 txt.push(":");
454 txt.push(elem.tag_name().name());
455 txt.push(" xmlns:");
456 txt.push(ns.name().unwrap());
457 txt.push("=");
458 txt.push("\"");
459 txt.push(ns.uri());
460 txt.push("\"");
461 }
462 }
463 else {
464 &txt.push(elem.tag_name().name());
465 }
466 &txt.push(">");
467
468 if elem.has_children() {
469 for c in elem.children() {
470
471 if c.is_element() {
472 &txt.push("<");
473 if c.namespaces().len() > 0 {
474 for ns in c.namespaces() {
475 txt.push(ns.name().unwrap());
476 txt.push(":");
477 txt.push(c.tag_name().name());
478 txt.push(" xmlns:");
479 txt.push(ns.name().unwrap());
480 txt.push("=");
481 txt.push("\"");
482 txt.push(ns.uri());
483 txt.push("\"");
484 }
485 }
486 else {
487 &txt.push(c.tag_name().name());
488 }
489 &txt.push(">");
490 match c.text() {
491 Some(t) => txt.push(t),
492 None => ()
493 }
494 &txt.push("</");
495 if c.namespaces().len() > 0 {
496 for n in c.namespaces() {
497 txt.push(n.name().unwrap());
498 txt.push(":");
499 }
500 }
501 &txt.push(c.tag_name().name());
502 &txt.push(">");
503 }
504 else {
505 match c.text() {
506 Some(t) => &txt.push(&t),
507 None => &txt.push("")
508 };
509 }
510
511
512 };
513 }else {
515 match elem.text() {
516 Some(t) => &txt.push(&t),
517 None => &txt.push("")
518 };
519 }
520
521 &txt.push("</");
522 if elem.namespaces().len() > 0 {
523 for ns in elem.namespaces() {
524 txt.push(ns.name().unwrap());
525 txt.push(":");
526 }
527 }
528 &txt.push(elem.tag_name().name());
529 &txt.push(">");
530 }
531 abstract_text.value = Some(txt.concat())
532 }
533
534 abstract_text
535 }
536}
537impl FromXMLNode for Abstract {
538 fn from_node(node: &Node) -> Self {
539 let mut abs = Abstract {
540 text: Vec::new()
541 };
542
543 for elem in node
544 .children()
545 .filter(|e| e.is_element()) {
546 match elem.tag_name().name() {
547 "AbstractText" => abs.text.push(
548 AbstractText::from_node(&elem)
549 ),
550 _ => ()
551 }
552 }
553
554 abs
555
556 }
557}
558impl FromXMLNode for Article {
559 fn from_node(node: &Node) -> Self {
560 let mut article = Article {
561 pub_model: node.attribute("PubModel")
562 .map(|a| a.to_string()),
563 title: None,
564 journal: None,
565 elocation_id: None,
566 language: None,
567 abstract_text: None
568
569 };
570
571 for elem in node
572 .children()
573 .filter(|e| e.is_element()) {
574
575 match elem.tag_name().name() {
576 "ArticleTitle" => {
577 article.title = elem.text()
578 .map(|e| e.to_string())
579 },
580 "Journal" => {
581 article.journal = Some(Journal::from_node(&elem))
582 },
583 "ELocationID" => {
584 article.elocation_id = Some(ELocationID::from_node(&elem))
585 },
586 "Language" => {
587 article.language = elem.text()
588 .map(|e| e.to_string())
589 },
590 "Abstract" => {
591 article.abstract_text = Some(Abstract::from_node(&elem))
592 },
593 _ => ()
594 }
595 }
596 article
597 }
598}
599impl FromXMLNode for MedlineJournalInfo {
600 fn from_node(node: &Node) -> Self {
601 let mut med_journ_info = MedlineJournalInfo {
602 country: None,
603 medline_ta: None,
604 nlm_unique_id: None,
605 issn_linking: None
606 };
607
608 for elem in node
609 .children()
610 .filter(|e| e.is_element()) {
611 match elem.tag_name().name() {
612 "Country" => {
613 med_journ_info
614 .country = elem.text().map(|t| t.to_string())
615 },
616 "MedlineTA" => {
617 med_journ_info
618 .medline_ta = elem.text().map(|t| t.to_string())
619 },
620 "NlmUniqueID" => {
621 med_journ_info
622 .nlm_unique_id = elem.text().map(|t| t.to_string())
623 },
624 "ISSNLinking" => {
625 med_journ_info
626 .issn_linking = elem.text().map(|t| t.to_string())
627 },
628 _ => ()
629
630 }
631 }
632 med_journ_info
633 }
634}
635impl FromXMLNode for MedlineCitation {
636 fn from_node(node: &Node) -> Self {
637 let mut medline_citation = MedlineCitation {
638 status: node.attribute("Status")
639 .map(|s| s.to_string()),
640
641 owner: node.attribute("Owner")
642 .map(|s| s.to_string()),
643 pmid: None,
644
645 date_revised: None,
646
647 article: None,
648
649 medline_journal_info: None
650 };
651
652 for elem in node
653 .children()
654 .filter(|e| e.is_element()) {
655 match elem.tag_name().name() {
656 "PMID" => medline_citation.pmid = Some(PMID::from_node(&elem)),
657 "DateRevised" => medline_citation.date_revised = Some(PubDate::from_node(&elem)),
658 "Article" => medline_citation.article = Some(Article::from_node(&elem)),
659 "MedlineJournalInfo" => medline_citation.medline_journal_info = Some(MedlineJournalInfo::from_node(&elem)),
660 _ => ()
661 }
662 }
663
664 medline_citation
665
666 }
667}
668
669impl FromXMLNode for PubmedArticle {
671 fn from_node(node: &Node) -> Self {
672 let mut pub_art = PubmedArticle {
673 medline_citation: None,
674 pubmed_data: None
675 };
676
677 for elem in node
678 .children()
679 .filter(|e| e.is_element()) {
680 match elem.tag_name().name() {
681 "MedlineCitation" => pub_art.medline_citation = Some(MedlineCitation::from_node(&elem)),
682 "PubmedData" => pub_art.pubmed_data = Some(PubmedData::from_node(&elem)),
683 _ => ()
684 }
685 }
686
687 pub_art
688 }
689}
690
691impl FromXMLNode for PubmedArticleSet {
694 fn from_node(node: &Node) -> Self {
695 let mut pm_set = PubmedArticleSet {
696 articles: Vec::new()
697 };
698
699 for elem in node
700 .children()
701 .filter(|e| e.is_element()) {
702 match elem.tag_name().name() {
703 "PubmedArticle" => pm_set.articles.push(
704 PubmedArticle::from_node(&elem)
705 ),
706 _ => ()
707 }
708 }
709
710 pm_set
711 }
712}
713
714impl PubmedArticleSet {
715 pub fn read(xml: &str) -> Result<Self, Error> {
716
717 let pm_parsed = Document::parse(&xml)?;
718
719 let pm_art_node = &pm_parsed
720 .descendants()
721 .find(|n| n.has_tag_name("PubmedArticleSet")).unwrap();
722
723 let res = PubmedArticleSet::from_node(&pm_art_node);
724
725 Ok(res)
726 }
727}