All Projects → renggli → Dart Xml

renggli / Dart Xml

Licence: mit
Lightweight library for parsing, traversing, and transforming XML in Dart.

Programming Languages

dart
5743 projects

Projects that are alternatives of or similar to Dart Xml

Quick Xml
Rust high performance xml reader and writer
Stars: ✭ 480 (+245.32%)
Mutual labels:  xml, xml-parser
Fuzi
A fast & lightweight XML & HTML parser in Swift with XPath & CSS support
Stars: ✭ 894 (+543.17%)
Mutual labels:  xml, xml-parser
Libexpat
🌿 Expat library: Fast streaming XML parser written in C; in the process of migrating from SourceForge to GitHub
Stars: ✭ 549 (+294.96%)
Mutual labels:  xml, xml-parser
Camaro
camaro is an utility to transform XML to JSON, using Node.js binding to native XML parser pugixml, one of the fastest XML parser around.
Stars: ✭ 438 (+215.11%)
Mutual labels:  xml, xml-parser
Xslt Processor
A JavaScript XSLT processor without native library dependencies
Stars: ✭ 50 (-64.03%)
Mutual labels:  xml, xml-parser
Node Xml2js
XML to JavaScript object converter.
Stars: ✭ 4,402 (+3066.91%)
Mutual labels:  xml, xml-parser
Easyxml
Simplifies parsing and modifying of (huge) XML streams (files) based on the StAX parser with combination of JAXB or JDom2
Stars: ✭ 6 (-95.68%)
Mutual labels:  xml, xml-parser
fox
A Fortran XML library
Stars: ✭ 51 (-63.31%)
Mutual labels:  xml, xml-parser
Xml Js
Converter utility between XML text and Javascript object / JSON text.
Stars: ✭ 874 (+528.78%)
Mutual labels:  xml, xml-parser
Cheatyxml
CheatyXML is a Swift framework designed to manage XML easily
Stars: ✭ 23 (-83.45%)
Mutual labels:  xml, xml-parser
Tikxml
Modern XML Parser for Android
Stars: ✭ 370 (+166.19%)
Mutual labels:  xml, xml-parser
Android Gpx Parser
A library to parse XML Gpx files, built for Android.
Stars: ✭ 79 (-43.17%)
Mutual labels:  xml, xml-parser
Node Rest Client
REST API client from node.js
Stars: ✭ 365 (+162.59%)
Mutual labels:  xml, xml-parser
Xmlcoder
Easy XML parsing using Codable protocols in Swift
Stars: ✭ 460 (+230.94%)
Mutual labels:  xml, xml-parser
Hquery.php
An extremely fast web scraper that parses megabytes of invalid HTML in a blink of an eye. PHP5.3+, no dependencies.
Stars: ✭ 295 (+112.23%)
Mutual labels:  xml, xml-parser
Dasel
Query, update and convert data structures from the command line. Comparable to jq/yq but supports JSON, TOML, YAML, XML and CSV with zero runtime dependencies.
Stars: ✭ 759 (+446.04%)
Mutual labels:  xml, xml-parser
Posthtml
PostHTML is a tool to transform HTML/XML with JS plugins
Stars: ✭ 2,737 (+1869.06%)
Mutual labels:  xml, xml-parser
xgen
XSD (XML Schema Definition) parser and Go/C/Java/Rust/TypeScript code generator
Stars: ✭ 153 (+10.07%)
Mutual labels:  xml, xml-parser
Xylophone
Xylophone
Stars: ✭ 23 (-83.45%)
Mutual labels:  xml, xml-parser
Oga
Read-only mirror of https://gitlab.com/yorickpeterse/oga
Stars: ✭ 1,147 (+725.18%)
Mutual labels:  xml, xml-parser

Dart XML

Pub Package Build Status Coverage Status GitHub Issues GitHub Forks GitHub Stars GitHub License

Dart XML is a lightweight library for parsing, traversing, querying, transforming and building XML documents.

This library is open source, stable and well tested. Development happens on GitHub. Feel free to report issues or create a pull-request there. General questions are best asked on StackOverflow.

The package is hosted on dart packages. Up-to-date class documentation is created with every release.

Tutorial

Installation

Follow the installation instructions on dart packages.

Import the library into your Dart code using:

import 'package:xml/xml.dart';

Reading and Writing

To read XML input use the factory method XmlDocument.parse(String input):

final bookshelfXml = '''<?xml version="1.0"?>
    <bookshelf>
      <book>
        <title lang="english">Growing a Language</title>
        <price>29.99</price>
      </book>
      <book>
        <title lang="english">Learning XML</title>
        <price>39.95</price>
      </book>
      <price>132.00</price>
    </bookshelf>''';
final document = XmlDocument.parse(bookshelfXml);

The resulting object is an instance of XmlDocument. In case the document cannot be parsed, a XmlParserException is thrown.

To write back the parsed XML document, simply call toString() or toXmlString(...) if you need more control:

print(document.toString());
print(document.toXmlString(pretty: true, indent: '\t'));

To read XML from a file use the dart:io library:

final file = new File('bookshelf.xml');
final document = XmlDocument.parse(file.readAsStringSync());

If your file is not UTF-8 encoded pass the correct encoding to readAsStringSync. To read and write large files you might want to use the streaming API instead.

Traversing and Querying

Accessors allow accessing nodes in the XML tree:

  • attributes returns a list over the attributes of the current node.
  • children returns a list over the children of the current node.

Both lists are mutable and support all common List methods, such as add(XmlNode), addAll(Iterable<XmlNode>), insert(int, XmlNode), and insertAll(int, Iterable<XmlNode>). Trying to add a null value or an unsupported node type throws an XmlNodeTypeError error. Nodes that are already part of a tree are not automatically moved, you need to first create a copy as otherwise an XmlParentError is thrown. XmlDocumentFragment nodes are automatically expanded and copies of their children are added.

There are various methods to traverse the XML tree along its axes:

  • preceding returns an iterable over nodes preceding the opening tag of the current node in document order.
  • descendants returns an iterable over the descendants of the current node in document order. This includes the attributes of the current node, its children, the grandchildren, and so on.
  • following the nodes following the closing tag of the current node in document order.
  • ancestors returns an iterable over the ancestor nodes of the current node, that is the parent, the grandparent, and so on. Note that this is the only iterable that traverses nodes in reverse document order.

For example, the descendants iterator could be used to extract all textual contents from an XML tree:

final textual = document.descendants
  .where((node) => node is XmlText && !node.text.trim().isEmpty)
  .join('\n');
print(textual);

Additionally, there are helpers to find elements with a specific tag:

  • getElement(String name) finds the first direct child with the provided tag name, or null.
  • findElements(String name) finds direct children of the current node with the provided tag name.
  • findAllElements(String name) finds direct and indirect children of the current node with the provided tag name.

For example, to find all the nodes with the <title> tag you could write:

final titles = document.findAllElements('title');

The above code returns a lazy iterator that recursively walks the XML document and yields all the element nodes with the requested tag name. To extract the textual contents call text:

titles
    .map((node) => node.text)
    .forEach(print);

This prints Growing a Language and Learning XML.

Similarly, to compute the total price of all the books one could write the following expression:

final total = document.findAllElements('book')
    .map((node) => double.parse(node.findElements('price').single.text))
    .reduce((a, b) => a + b);
print(total);

Note that this first finds all the books, and then extracts the price to avoid counting the price tag that is included in the bookshelf.

Building

While it is possible to instantiate and compose XmlDocument, XmlElement and XmlText nodes manually, the XmlBuilder provides a simple fluent API to build complete XML trees. To create the above bookshelf example one would write:

final builder = XmlBuilder();
builder.processing('xml', 'version="1.0"');
builder.element('bookshelf', nest: () {
  builder.element('book', nest: () {
    builder.element('title', nest: () {
      builder.attribute('lang', 'en');
      builder.text('Growing a Language');
    });
    builder.element('price', nest: 29.99);
  });
  builder.element('book', nest: () {
    builder.element('title', nest: () {
      builder.attribute('lang', 'en');
      builder.text('Learning XML');
    });
    builder.element('price', nest: 39.95);
  });
  builder.element('price', nest: 132.00);
});
final bookshelfXml = builder.buildDocument();

The element method supports optional named arguments:

  • The most common is the nest: argument which is used to insert contents into the element. In most cases this will be a function that calls more methods on the builder to define attributes, declare namespaces and add child elements. However, the argument can also be a string or an arbitrary Dart object that is converted to a string and added as a text node.
  • While attributes can be defined from within the element, for simplicity there is also an argument attributes: that takes a map to define simple name-value pairs.
  • Furthermore, we can provide a URI as the namespace of the element using namespace: and declare new namespace prefixes using namespaces:. For details see the documentation of the method.

The builder pattern allows you to easily extract repeated parts into specific methods. In the example above, one could put the part writing a book into a separate method as follows:

void buildBook(XmlBuilder builder, String title, String language, num price) {
  builder.element('book', nest: () {
    builder.element('title', nest: () {
      builder.attribute('lang', language);
      builder.text(title);
    });
    builder.element('price', nest: price);
  });
}

The above buildDocument() method returns the built document. To attach built nodes into an existing XML document, use buildFragment(). Once the builder returns the built node, its internal state is reset.

final builder = XmlBuilder();
buildBook(builder, 'The War of the Worlds', 'en', 12.50);
buildBook(builder, 'Voyages extraordinaries', 'fr', 18.20);
bookshelfXml.firstElementChild.children.add(builder.buildFragment());

Event-driven

Reading large XML files and instantiating their DOM into the memory can be expensive. As an alternative this library provides the possibility to read and transform XML documents as a sequence of events using Dart Iterables or Streams. These approaches are comparable to event-driven SAX parsing known from other libraries.

import 'package:xml/xml_events.dart';

Iterables

In the simplest case you can get a Iterable<XmlEvent> over the input string using the following code. This parses the input lazily, and only parses input when requested:

parseEvents(bookshelfXml)
    .whereType<XmlTextEvent>()
    .map((event) => event.text.trim())
    .where((text) => text.isNotEmpty)
    .forEach(print);

This approach requires the whole input to be available at the beginning and does not work if the data itself is only available asynchronous, such as coming from a slow network connection. A more sophisticated API is provided with Dart Streams.

Streams

To asynchronously parse and process events directly from a file or HTTP stream use the provided codecs to convert between strings, events and DOM tree nodes:

  • Codec: XmlEventCodec
    • Decodes a String to a sequence of XmlEvent objects.
      Stream<List<XmlEvent>> toXmlEvents() on Stream<String>
    • Encodes a sequence of XmlEvent objects to a String.
      Stream<String> toXmlString() on Stream<List<XmlEvent>>
  • Codec: XmlNodeCodec
    • Decodes a sequence of XmlEvent objects to XmlNode objects.
      Stream<List<XmlNode>> toXmlNodes() on Stream<List<XmlEvent>>
    • Encodes a sequence of XmlNode objects to XmlEvent objects.
      Stream<List<XmlEvent>> toXmlEvents() on Stream<List<XmlNode>>

Various transformations are provided to simplify processing complex streams:

  • Normalizes a sequence of XmlEvent objects by removing empty and combining adjacent text events.
    Stream<List<XmlEvent>> normalizeEvents() on Stream<List<XmlEvent>>
  • Annotates XmlEvent objects with their parent events that is thereafter accessible through XmlParented.parentEvent. Validates the nesting and throws an exception if it is invalid.
    Stream<List<XmlEvent>> withParentEvents() on Stream<List<XmlEvent>>
  • From a sequence of XmlEvent objects filter the event sequences that form sub-trees for which a predicate returns true.
    Stream<List<XmlEvent>> selectSubtreeEvents(Predicate<XmlStartElementEvent>) on Stream<List<XmlEvent>>
  • Flattens a chunked stream of objects to a stream of objects.
    Stream<T> flatten() on Stream<Iterable<T>>
  • Executes the provided callbacks on each event of this stream.
    Future forEachEvent({onText: ...}) on Stream<XmlEvent>.

For example, the following snippet downloads data from the Internet, converts the UTF-8 input to a Dart String, decodes the stream of characters to XmlEvents, and finally normalizes and prints the events:

final url = Uri.parse('http://ip-api.com/xml/');
final request = await HttpClient().getUrl(url);
final response = await request.close();
await response
  .transform(utf8.decoder)
  .toXmlEvents()
  .normalizeEvents()
  .forEachEvent(onText: (event) => print(event.text));

Similarly, the following snippet extracts sub-trees with location information from a sitemap.xml file, converts the XML events to XML nodes, and finally prints out the containing text:

final file = File('sitemap.xml');
await file.openRead()
  .transform(utf8.decoder)
  .toXmlEvents()
  .selectSubtreeEvents((event) => event.name == 'loc')
  .toXmlNodes()
  .forEach((node) => print(node.innerText));

A common challenge when processing XML event streams is the lack of hierarchical information, thus it is very hard to figure out parent dependencies such as looking up a namespace URI. The .withParentEvents() transformation validates the hierarchy and annotates the events with their parent event. This enables features (such as parentEvent and the namespaceUri accessor) and makes mapping and selecting events considerably simpler. For example:

await Stream.fromIterable([shiporderXsd])
  .toXmlEvents()
  .withParentEvents()
  .selectSubtreeEvents((event) =>
      event.localName == 'element' &&
      event.namespaceUri == 'http://www.w3.org/2001/XMLSchema')
  .toXmlNodes()
  .forEach((node) => print(node.toXmlString(pretty: true)));

Misc

Examples

This package comes with several examples.

Furthermore, there are numerous packages depending on this package:

Supports

  • Standard well-formed XML (and HTML).
  • Reading documents using an event based API (SAX).
  • Decodes and encodes commonly used character entities.
  • Querying, traversing, and mutating API using Dart principles.
  • Building XML trees using a builder API.

Limitations

  • Doesn't validate namespace declarations.
  • Doesn't validate schema declarations.
  • Doesn't parse and enforce the DTD.

Standards

History

This library started as an example of the PetitParser library. To my own surprise various people started to use it to read XML files. In April 2014 I was asked to replace the original dart-xml library from John Evans.

License

The MIT License, see LICENSE.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].