import 'package:test/test.dart'; import 'package:xml/xml.dart'; import 'package:xml/xml_events.dart'; import 'package:xml/xpath.dart'; import 'utils/assertions.dart'; import 'utils/examples.dart'; class TrimTextVisitor with XmlVisitor { @override void visitDocument(XmlDocument node) => node.children.forEach(visit); @override void visitElement(XmlElement node) => node.children.forEach(visit); @override void visitText(XmlText node) => node.value = node.value.trim(); } void main() { test('https://github.com/renggli/dart-xml/issues/38', () { const input = '' '0xd8d5b9000000b3e80x00135003007c27b4' '0x2244aeb30x0006c1' '0x000000010x000003e8' '0x030x0f' 'Y' ''; assertDocumentParseInvariants(input); }); test('https://github.com/renggli/dart-xml/issues/95', () { const input = ''' '''; assertFragmentParseInvariants(input); final fragment = XmlDocumentFragment.parse(input); final href = fragment .findElements('link') .where( (element) => element.getAttribute('rel') == 'http://opds-spec.org/image/thumbnail', ) .map((element) => element.getAttribute('href')) .single; expect( href, 'https://covers.feedbooks.net/book/2936.jpg?size=large&t=1549045871', ); }); group('https://github.com/renggli/dart-xml/issues/99', () { const input = ''' left both right '''; test('transformation class', () { final document = XmlDocument.parse(input); TrimTextVisitor().visit(document); expect(document.rootElement.children[1].innerText, 'left'); expect(document.rootElement.children[3].innerText, 'both'); expect(document.rootElement.children[5].innerText, 'right'); }); test('transformation function', () { final document = XmlDocument.parse(input); for (final node in document.descendants.whereType()) { node.replace(XmlText(node.value.trim())); } expect(document.rootElement.children[1].innerText, 'left'); expect(document.rootElement.children[3].innerText, 'both'); expect(document.rootElement.children[5].innerText, 'right'); }); }); test('https://github.com/renggli/dart-xml/issues/100', () { final document = XmlDocument.parse(''' 0 50 1 '''); expect(document.rootElement.getElement('os:totalResults')?.innerText, '0'); expect(document.rootElement.getElement('os:itemsPerPage')?.innerText, '50'); expect(document.rootElement.getElement('os:startIndex')?.innerText, '1'); }); test('https://github.com/renggli/dart-xml/issues/104', () { final document = XmlDocument.parse(''' %PersProse; ]> '''); expect(document.doctypeElement, isNotNull); expect(document.doctypeElement!.name, 'TEI.2'); expect( document.doctypeElement!.externalId!.publicId, '-//TEI P4//DTD Main DTD Driver File//EN', ); expect( document.doctypeElement!.externalId!.systemId, 'http://www.tei-c.org/Guidelines/DTD/tei2.dtd', ); }); test('https://stackoverflow.com/questions/68100391', () { const number = 20; final document = XmlDocument.parse(''' 80 '''); document.findAllElements('AlarmVolume').first.innerText = number.toString(); expect(document.toXmlString(), ''' 20 '''); }); test('https://github.com/renggli/dart-xml/issues/144', () { assertDocumentParseInvariants(''' ]>'''); }); test('https://github.com/renggli/dart-xml/discussions/142', () { final entityMapping = XmlDefaultEntityMapping({ ...const XmlDefaultEntityMapping.html5().entities, 'O': '\u201C', 'C': '\u201D', }); final document = XmlDocument.parse(''' ]> Alice's Adventures in Wonderland by Lewis Carroll &O;Who are you?&C; said the Caterpillar. ''', entityMapping: entityMapping); expect( document.findAllElements('body').first.innerText, '“Who are you?” said the Caterpillar.', ); }); group('https://github.com/renggli/dart-xml/discussions/154', () { final document = XmlDocument.parse( '' '1' // first match '2' // second match '3' // third match (does not descend into inner) '', ); bool predicate(XmlNode node) => node is XmlElement && node.localName == 'x'; test('descendants & ancestors', () { final nodes = document.descendants // Find all the nodes that satisfy the condition. .where(predicate) // Exclude the nodes that have parents satisfying the condition. .where((node) => !node.ancestors.any(predicate)); expect(nodes.map((node) => node.innerText), ['1', '2', '3']); }); test('recursive', () { List find(XmlNode node, bool Function(XmlNode) predicate) { if (predicate(node)) { // Return a matching node, ... return [node]; } else { // ... otherwise recurse into the children. return [ ...node.attributes.expand((child) => find(child, predicate)), ...node.children.expand((child) => find(child, predicate)), ]; } } final nodes = find(document, predicate); expect(nodes.map((node) => node.innerText), ['1', '2', '3']); }); test('iterative', () { List find(XmlNode node, bool Function(XmlNode) predicate) { final todo = [node]; final solutions = []; while (todo.isNotEmpty) { final current = todo.removeAt(0); if (predicate(current)) { solutions.add(current); } else { todo.insertAll(0, current.nodes); } } return solutions; } final nodes = find(document, predicate); expect(nodes.map((node) => node.innerText), ['1', '2', '3']); }); }); test('https://github.com/renggli/dart-xml/issues/156', () { const bookshelfXml = ''' '''; final document = XmlDocument.parse(bookshelfXml); final carElement = document.rootElement; expect(carElement.getAttribute('color:name'), equals('blue')); // In 6.2.1, this creates another color:name // attribute instead of overwriting the existing one. carElement.setAttribute('color:name', 'red'); expect(carElement.getAttribute('color:name'), equals('red')); }); test('https://github.com/renggli/dart-xml/issues/160', () { const xml = '\r\n' '\r\n' ' \r\n' ''; final doc = XmlDocument.parse(xml); // https://www.w3.org/TR/xml11/#sec-line-ends doc.normalize(normalizeAllNewline: true); final textNode = doc.rootElement.firstChild!; expect(textNode.nodeType, XmlNodeType.TEXT); expect(textNode.value, equals('\n ')); }); test('https://github.com/renggli/dart-xml/discussions/168', () { final actual = XmlDocument.parse( '', ); final image = actual.findAllElements('IMG').single; final blur = image.findAllElements('BLUR').single; image.children.remove(blur); image.replace(blur); blur.children.add(image); final expected = XmlDocument.parse( '', ); expect(expected.toXmlString(), actual.toXmlString()); }); group('https://github.com/renggli/dart-xml/discussions/177', () { const input = 'ab'; test('iterable', () { var started = false; final found = []; for (final event in parseEvents(input)) { if (event is XmlStartElementEvent && event.name == 'item') { started = true; } else if (event is XmlEndElementEvent && event.name == 'item') { started = false; } else if (started) { found.add(event); // an event that is part of `...` } } expect(found, [XmlTextEvent('a'), XmlTextEvent('b')]); }); test('stream', () async { final result = await Stream.value(input) .toXmlEvents() .normalizeEvents() .selectSubtreeEvents((event) => event.name == 'item') .toXmlNodes() .expand((nodes) => nodes) .toList(); expect(result.map((each) => each.toString()), [ 'a', 'b', ]); }); }); test('https://stackoverflow.com/questions/77055363', () { final xml = XmlDocument.parse(booksXml); final result = xml.xpath('//book[contains(@id, "106")]/title'); expect(result.map((each) => each.innerText), ['Lover Birds']); }); }