{"id":28327464,"url":"https://github.com/minidom/minidom","last_synced_at":"2025-06-24T05:31:13.182Z","repository":{"id":46647666,"uuid":"85785045","full_name":"MiniDOM/MiniDOM","owner":"MiniDOM","description":"Minimal XML DOM for Swift","archived":false,"fork":false,"pushed_at":"2021-11-18T14:55:01.000Z","size":835,"stargazers_count":9,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-02T12:03:35.311Z","etag":null,"topics":["dom","swift","xml"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MiniDOM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-22T04:29:34.000Z","updated_at":"2023-11-04T02:14:30.000Z","dependencies_parsed_at":"2022-09-16T11:30:35.219Z","dependency_job_id":null,"html_url":"https://github.com/MiniDOM/MiniDOM","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/MiniDOM/MiniDOM","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiniDOM%2FMiniDOM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiniDOM%2FMiniDOM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiniDOM%2FMiniDOM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiniDOM%2FMiniDOM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MiniDOM","download_url":"https://codeload.github.com/MiniDOM/MiniDOM/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiniDOM%2FMiniDOM/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261613609,"owners_count":23184438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dom","swift","xml"],"created_at":"2025-05-26T03:14:58.402Z","updated_at":"2025-06-24T05:31:13.173Z","avatar_url":"https://github.com/MiniDOM.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MiniDOM: Minimal XML DOM for Swift\n\n[![Platform](https://img.shields.io/cocoapods/p/MiniDOM.svg)](https://minidom.github.io/Documentation)\n![License](https://img.shields.io/cocoapods/l/MiniDOM.svg)\n\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/MiniDOM.svg)](https://img.shields.io/cocoapods/v/MiniDOM.svg)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg)](https://github.com/Carthage/Carthage)\n![Swift Package Manager Compatible](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange.svg)\n\n[![codecov.io](https://codecov.io/gh/MiniDOM/MiniDOM/branch/master/graphs/badge.svg)](https://codecov.io/gh/MiniDOM/MiniDOM/branch/master)\n![Documentation Status](https://minidom.github.io/Documentation/badge.svg)\n\n## Introduction\n\nMiniDOM is a minimal implementation of the Document Object Model interface. It is intended to be simpler than the full DOM but full-featured enough to be useful in most applications.\n\nMiniDOM is fully [documented](https://minidom.github.io/Documentation/) and [unit tested](https://codecov.io/gh/MiniDOM/MiniDOM/). It can be used on iOS, macOS, watchOS, and tvOS. The library is released under the MIT license.\n\nTo parse an XML document, simply create a `Parser` object and call `parse()`:\n\n```swift\nimport Foundation\nimport MiniDOM\n\nfunc parseXML(url: URL) -\u003e Document? {\n    let parser = Parser(contentsOf: url)\n    let result = parser?.parse()\n    return result?.document\n}\n```\n\nThe resulting structure is a tree of objects implementing the `Node` protocol: `Document`, `Element`, `Text`, `ProcessingInstruction`, `Comment`, and `CDATASection`. Accessor methods and properties are provided that are similar to those in the DOM specification. DOM trees can be traversed using search methods, path-evaluation methods, or using the visitor design pattern. Each of these will be discussed in detail below.\n\n## Installing\n\nMiniDOM supports installation via the CocoaPods, Carthage, and the Swift Package Manager.\n\n### CocoaPods\n\nAdd the following to your `Podfile`:\n\n    pod 'MiniDOM'\n\n### Carthage\n\nAdd the following to your `Cartfile`:\n\n    github \"MiniDOM/MiniDOM\"\n\n### Swift Package Manager\n\nAdd the following dependency to your `Package.swift` file:\n\n    .package(url: \"https://github.com/MiniDOM/MiniDOM/\", from: \"1.0.0\")\n\n### Dependencies\n\nMiniDOM has no third-party dependencies. It only uses `Foundation` classes, including `XMLParser`. Unit tests are written using `XCUnit`.\n\n## Path evaluation\n\nMiniDOM provides a mechanism for traversing a document via a path. Call `Document.evaluate(path:)`, passing an array of strings representing element node names (`Node.nodeName`). For example, consider the following document:\n\n```xml\n\u003ca id=\"1\"\u003e\n  \u003cb id=\"2\"\u003e\n    \u003cz id=\"3\"/\u003e\n  \u003c/b\u003e\n  \u003cc id=\"4\"\u003e\n    \u003cz id=\"5\"/\u003e\n  \u003c/c\u003e\n  \u003cb id=\"6\"/\u003e\n  \u003cz id=\"7\"/\u003e\n  \u003cb id=\"8\"\u003e\n    \u003cz id=\"9\"/\u003e\n  \u003c/b\u003e\n\u003c/a\u003e\n```\n\nEvaluating the path `[\"a\", \"b\", \"z\"]` (by calling `document.evaluate(path: [\"a\", \"b\", \"z\"])`) will return an array of two `Element` objects representing the `\u003cz\u003e` elements with ID `3` and `9`.\n\n## Visitor design pattern\n\nThe [Visitor Design Pattern](https://en.wikipedia.org/wiki/Visitor_pattern) is used throughout the MiniDOM library to implement algorithms that involve traversing the DOM tree. It provides a convenient mechanism to separate an algorithm from the object structure on which it operates. It allows operations to be added to the DOM structure without modifying the structures themselves.\n\nA `Visitor` object is provided to `Node.accept(_:)` to start the traversal. The `Node` object calls the appropriate methods on the `Visitor` object before calling `Node.accept(_:)` on its child nodes, performing the recursive traversal.\n\nThe `Visitor` protocol defines methods that correspond to each of the `Node` types in the DOM. Types implementing the `Visitor` protocol do not need to deal with the actual traversal; its methods are called by the traversal algorithm provided by the DOM classes.\n\nFor a simple example of a visitor, see the `ElementSearch` class in `Search.swift`. For a more complex example of a visitor, see the `PrettyPrinter` class in `Formatter.swift`.\n\n## Example\n\nThe following is taken from `MiniDOM.playground` in the root of the project. Feel free to open it up and experiment on your own.\n\n### Parsing a document\n\nWe have an XML document saved in the resources section of the playground. It contains a snapshot of the EFF Updates RSS feed. We'll begin by parsing the document.\n\n```swift\nlet url = Bundle.main.url(forResource: \"eff-updates\", withExtension: \"rss\")!\nlet parser = Parser(contentsOf: url)\nlet document = parser?.parse().document\n```\n\n### Walking through the document\n\nThe document's structure is something like this:\n\n```xml\n\u003crss\u003e\n    \u003cchannel\u003e\n        \u003ctitle\u003e...\u003c/title\u003e\n        \u003clink\u003e...\u003c/link\u003e\n        \u003cdescription\u003e...\u003c/description\u003e\n        \u003citem\u003e\n            \u003ctitle\u003e...\u003c/title\u003e\n            \u003clink\u003e...\u003c/link\u003e\n            \u003cdescription\u003e...\u003c/description\u003e\n        \u003c/item\u003e\n        \u003citem\u003e...\u003c/item\u003e\n        ...\n    \u003c/channel\u003e\n\u003c/rss\u003e\n```\n\nLet's begin by getting the document element or root node of the document.\n\n```swift\nlet rss = document?.documentElement\nrss?.nodeName\n```\n\n**Result**\n```\n\"rss\"\n```\n\nThe `\u003crss\u003e` element should have one child: a `\u003cchannel\u003e` element.\n\n```swift\nlet channel = rss?.firstChildElement\nchannel?.nodeName\n```\n\n**Result**\n```\n\"channel\"\n```\n\nThe `\u003cchannel\u003e` element should have 50 `\u003citem\u003e` children.\n\n```swift\nlet items = channel?.childElements(withName: \"item\")\nitems?.count\n```\n\n**Result**\n```\n50\n```\n\nEach of the `\u003citem\u003e` elements should have a `\u003ctitle\u003e` child.\n\n```swift\nlet itemTitles = items?.flatMap { itemElement -\u003e String? in\n    let titleElement = itemElement.childElements(withName: \"title\").first\n    return titleElement?.textValue\n}\nitemTitles\n```\n\n**Result**\n```\n0 \"Stupid Patent of the Month: Storing Files in Folders\"\n1 \"NAFTA Renegotiation Will Resurrect Failed TPP Proposals\"\n2 \"New Report Aims to Help Criminal Defense Attorneys Challenge Secretive Government Hacking\"\n3 \"The Most Powerful Single Click in Your Facebook Privacy Settings\"\n4 \"Repealing Broadband Privacy Rules, Congress Sides with the Cable and Telephone Industry\"\n...\n```\n\nThere are `\u003clink\u003e` elements that are children of the `\u003cchannel\u003e` element, and that are children of each of the `\u003citem\u003e` elements. We can find all of them.\n\n```swift\nlet linkElementsFromDocument = document?.elements(withTagName: \"link\")\nlet linkURLsFromDocument = linkElementsFromDocument?.flatMap { $0.textValue }\nlinkURLsFromDocument\n```\n\n**Result**\n```\n0 \"https://www.eff.org/rss/updates.xml\"\n1 \"https://www.eff.org/deeplinks/2017/03/stupid-patent-month-storing-files-folders\"\n2 \"https://www.eff.org/deeplinks/2017/03/nafta-renegotiation-will-resurrect-failed-tpp-proposals\"\n3 \"https://www.eff.org/deeplinks/2017/03/eff-says-no-so-called-moral-rights-copyright-expansion\"\n4 \"https://www.eff.org/deeplinks/2017/03/new-report-aims-help-criminal-defense-attorneys-challenge-secretive-government\"\n5 \"https://www.eff.org/deeplinks/2017/03/most-powerful-single-click-your-facebook-privacy-settings\"\n...\n```\n\n### Path evaluation\n\nThe `\u003citem\u003e` children of the `\u003cchannel\u003e` element should each have a `\u003clink\u003e` child. Using a path expression, we can collect all of the text children of the `\u003clink\u003e` elements under the `\u003cchannel\u003e` element.\n\n```swift\nlet linkTextNodesViaPath = document?.evaluate(path: [\"rss\", \"channel\", \"item\", \"link\", \"#text\"])\nlet linkURLsViaPath = linkTextNodesViaPath?.flatMap { $0.nodeValue }\nlinkURLsViaPath\n```\n\n**Result**\n```\n0 \"https://www.eff.org/deeplinks/2017/03/stupid-patent-month-storing-files-folders\"\n1 \"https://www.eff.org/deeplinks/2017/03/nafta-renegotiation-will-resurrect-failed-tpp-proposals\"\n2 \"https://www.eff.org/deeplinks/2017/03/eff-says-no-so-called-moral-rights-copyright-expansion\"\n3 \"https://www.eff.org/deeplinks/2017/03/new-report-aims-help-criminal-defense-attorneys-challenge-secretive-government\"\n4 \"https://www.eff.org/deeplinks/2017/03/most-powerful-single-click-your-facebook-privacy-settings\"\n...\n```\n\n### Visitor\n\nWe can collect all of the `\u003ctitle\u003e` elements in the document using a visitor.\n\n```swift\nclass TitleCollector: Visitor {\n    var titles: [String] = []\n\n    public func beginVisit(_ element: Element) {\n        if element.tagName == \"title\", let title = element.textValue {\n            titles.append(title)\n        }\n    }\n}\n\nlet titleCollector = TitleCollector()\ndocument?.accept(titleCollector)\ntitleCollector.titles\n```\n\n**Result**\n```\n0 \"Deeplinks\"\n1 \"Stupid Patent of the Month: Storing Files in Folders\"\n2 \"NAFTA Renegotiation Will Resurrect Failed TPP Proposals\"\n3 \"New Report Aims to Help Criminal Defense Attorneys Challenge Secretive Government Hacking\"\n4 \"The Most Powerful Single Click in Your Facebook Privacy Settings\"\n5 \"Repealing Broadband Privacy Rules, Congress Sides with the Cable and Telephone Industry\"\n```\n\n## Issues and Contributions\n\nPlease [report](https://github.com/MiniDOM/MiniDOM/issues) any issues you find.\n\nPull requests are welcome. Please make sure any additions are documented and unit tested. We aim to maintain 100% documentation and test coverage.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminidom%2Fminidom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminidom%2Fminidom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminidom%2Fminidom/lists"}