1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use xmlparser::{ElementEnd, Token};

use crate::{XmlError, XmlReader, XmlResult};

pub fn read_to_end(reader: &mut XmlReader<'_>, tag: &str) -> XmlResult<()> {
    while let Some(token) = reader.next() {
        match token? {
            // if this element is emtpy, just return
            Token::ElementEnd {
                end: ElementEnd::Empty,
                ..
            } => return Ok(()),
            Token::ElementEnd {
                end: ElementEnd::Open,
                ..
            } => break,
            Token::Attribute { .. } => (),
            // there shouldn't have any token but Attribute between ElementStart and ElementEnd
            token => {
                return Err(XmlError::UnexpectedToken {
                    token: format!("{:?}", token),
                })
            }
        }
    }

    let mut depth = 1;

    while let Some(token) = reader.next() {
        match token? {
            Token::ElementStart { span, .. } if tag == &span.as_str()[1..] => {
                while let Some(token) = reader.next() {
                    match token? {
                        Token::ElementEnd {
                            end: ElementEnd::Empty,
                            ..
                        } => {
                            if depth == 0 {
                                return Ok(());
                            } else {
                                // don't advance depth in this case
                                break;
                            }
                        }
                        Token::ElementEnd {
                            end: ElementEnd::Open,
                            ..
                        } => {
                            depth += 1;
                            break;
                        }
                        Token::Attribute { .. } => (),
                        // there shouldn't have any token but Attribute between ElementStart and ElementEnd
                        token => {
                            return Err(XmlError::UnexpectedToken {
                                token: format!("{:?}", token),
                            });
                        }
                    }
                }
            }
            Token::ElementEnd {
                end: ElementEnd::Close(_, _),
                span,
            } if tag == &span.as_str()[2..span.as_str().len() - 1] => {
                depth -= 1;
                if depth == 0 {
                    return Ok(());
                }
            }
            _ => (),
        }
    }

    Err(XmlError::UnexpectedEof)
}

#[test]
fn test_read_to_end() -> XmlResult<()> {
    use xmlparser::Tokenizer;

    let mut reader = Tokenizer::from("<parent><child/></parent>").peekable();

    assert!(reader.next().is_some()); // "<parent"
    assert!(reader.next().is_some()); // ">"
    assert!(reader.next().is_some()); // "<child"
    read_to_end(&mut reader, "child")?;
    assert!(reader.next().is_some()); // "</parent>"
    assert!(reader.next().is_none());

    let mut reader = Tokenizer::from("<parent><child></child></parent>").peekable();

    assert!(reader.next().is_some()); // "<parent"
    assert!(reader.next().is_some()); // ">"
    assert!(reader.next().is_some()); // "<child"
    read_to_end(&mut reader, "child")?;
    assert!(reader.next().is_some()); // "</parent>"
    assert!(reader.next().is_none());

    let mut reader = Tokenizer::from("<parent><child><child/></child></parent>").peekable();

    assert!(reader.next().is_some()); // "<parent"
    assert!(reader.next().is_some()); // ">"
    assert!(reader.next().is_some()); // "<child"
    read_to_end(&mut reader, "child")?;
    assert!(reader.next().is_some()); // "</parent>"
    assert!(reader.next().is_none());

    let mut reader = Tokenizer::from("<parent><child><child></child></child></parent>").peekable();

    assert!(reader.next().is_some()); // "<parent"
    assert!(reader.next().is_some()); // ">"
    assert!(reader.next().is_some()); // "<child"
    read_to_end(&mut reader, "child")?;
    assert!(reader.next().is_some()); // "</parent>"
    assert!(reader.next().is_none());

    Ok(())
}