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 = '- a
- b
';
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']);
});
}