{"id":1744,"url":"https://github.com/cezheng/Fuzi","last_synced_at":"2025-08-06T14:31:18.677Z","repository":{"id":1372862,"uuid":"42509230","full_name":"cezheng/Fuzi","owner":"cezheng","description":"A fast \u0026 lightweight XML \u0026 HTML parser in Swift with XPath \u0026 CSS support","archived":false,"fork":false,"pushed_at":"2024-07-12T23:44:01.000Z","size":645,"stargazers_count":1081,"open_issues_count":28,"forks_count":161,"subscribers_count":34,"default_branch":"master","last_synced_at":"2024-12-08T01:33:11.223Z","etag":null,"topics":["css","html","html-parser","html-parsing","ios","parser","parsing","swift","xml","xml-parser","xml-parsing","xpath"],"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/cezheng.png","metadata":{"files":{"readme":"README-ja.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-09-15T09:45:00.000Z","updated_at":"2024-12-06T07:33:58.000Z","dependencies_parsed_at":"2024-10-15T05:50:26.989Z","dependency_job_id":null,"html_url":"https://github.com/cezheng/Fuzi","commit_stats":{"total_commits":143,"total_committers":23,"mean_commits":6.217391304347826,"dds":"0.35664335664335667","last_synced_commit":"f08c8323da21e985f3772610753bcfc652c2103f"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cezheng%2FFuzi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cezheng%2FFuzi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cezheng%2FFuzi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cezheng%2FFuzi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cezheng","download_url":"https://codeload.github.com/cezheng/Fuzi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228840765,"owners_count":17980044,"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":["css","html","html-parser","html-parsing","ios","parser","parsing","swift","xml","xml-parser","xml-parsing","xpath"],"created_at":"2024-01-05T20:15:54.763Z","updated_at":"2024-12-09T14:31:15.649Z","avatar_url":"https://github.com/cezheng.png","language":"Swift","funding_links":[],"categories":["Parsing","Libs","JSON/XML Manipulation","Swift","Data and Storage","Network [🔝](#readme)"],"sub_categories":["XML \u0026 HTML","Network","Other free courses","Data Management"],"readme":"# Fuzi (斧子)\n\n[![Build Status](https://api.travis-ci.org/cezheng/Fuzi.svg)](https://travis-ci.org/cezheng/Fuzi)\n[![Cocoapods Compatible](https://img.shields.io/cocoapods/v/Fuzi.svg)](https://cocoapods.org/pods/Fuzi)\n[![License](https://img.shields.io/cocoapods/l/Fuzi.svg?style=flat\u0026color=gray)](http://opensource.org/licenses/MIT)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Platform](https://img.shields.io/cocoapods/p/Fuzi.svg?style=flat)](http://cezheng.github.io/Fuzi/)\n[![Twitter](https://img.shields.io/badge/twitter-@AdamoCheng-blue.svg?style=flat)](http://twitter.com/AdamoCheng)\n\n**軽くて、素早くて、 Swift の XML/HTML パーサー。** [[ドキュメント]](http://cezheng.github.io/Fuzi/)\n\nFuzi は Mattt Thompson氏の [Ono](https://github.com/mattt/Ono)(斧) に参照し Swift 言語で実装した XML/HTML パーサーである。\n\n\u003e Fuzi は漢字の`斧子`の中国語発音で、 意味は[Ono](https://github.com/mattt/Ono)(斧)と同じ。Onoは、[Nokogiri](http://nokogiri.org)(鋸)を参照し、創ったもの。\n\n[English](https://github.com/cezheng/Fuzi/blob/master/README.md)\n[简体中文](https://github.com/cezheng/Fuzi/blob/master/README-zh.md)\n## クイックルック\n```swift\nlet xml = \"...\"\n// or\n// let xmlData = \u003csome NSData or Data\u003e\ndo {\n  let document = try XMLDocument(string: xml)\n  // or\n  // let document = try XMLDocument(data: xmlData)\n  \n  if let root = document.root {\n    // Accessing all child nodes of root element\n    for element in root.children {\n      print(\"\\(element.tag): \\(element.attributes)\")\n    }\n    \n    // Getting child element by tag \u0026 accessing attributes\n    if let length = root.firstChild(tag:\"Length\", inNamespace: \"dc\") {\n      print(length[\"unit\"])     // `unit` attribute\n      print(length.attributes)  // all attributes\n    }\n  }\n  \n  // XPath \u0026 CSS queries\n  for element in document.xpath(\"//element\") {\n    print(\"\\(element.tag): \\(element.attributes)\")\n  }\n  \n  if let firstLink = document.firstChild(css: \"a, link\") {\n    print(firstLink[\"href\"])\n  }\n} catch let error {\n  print(error)\n}\n```\n\n## 機能\n### Onoから貰った機能\n- `libxml2`での素早いXMLパース\n- [XPath](http://en.wikipedia.org/wiki/XPath) と [CSS](http://en.wikipedia.org/wiki/Cascading_Style_Sheets) クエリ\n- 自動的にデータを日付や数字に変換する\n- XML ネイムスペース\n- `String` や `NSData` や `[CChar]`からXMLDocumentをロードする\n- 全面的なユニットテスト\n- 100%ドキュメント\n\n### Fuziの改善点\n- Swift 言語のネーミングやコーディングルールに沿って、クラスやメソッドを再設計した\n- 日付や数字変換のフォマットを指定できる\n- いくつかのバグ修正\n- より多くのHTML便利メソッド\n- 全種類のXMLノード取得可能（テキストノードやコメントノードなども含め）\n- より多くのCSSクエリ対応 (これから)\n\n\n\n## 環境\n\n- iOS 8.0+ / Mac OS X 10.9+\n- Xcode 8.0+\n\n\u003e Swift 2.3は[0.4.0](../../releases/tag/0.4.0)をご利用ください。\n\n## インストール\n### CocoaPodsで\n[Cocoapods](http://cocoapods.org/) で簡単に `Fuzi` をインストールできます。 下記のように`Podfile`を編集してください:\n\n```ruby\nplatform :ios, '8.0'\nuse_frameworks!\n\ntarget 'MyApp' do\n\tpod 'Fuzi', '~\u003e 1.0.0'\nend\n```\n\nそして、下記のコマンドを実行してください:\n\n```bash\n$ pod install\n```\n\n### 手動で\n1. `Fuzi`フォルダの `*.swift` ファイルをプロジェクトに追加してください。\n2. Xcode プロジェクトの `Build Settings` で:\n   1. `Search Paths`の`Header Search Paths`に`$(SDKROOT)/usr/include/libxml2`を追加してください。\n   2. `Linking`の`Other Linker Flags`に`-lxml2`を追加してください。\n\n### Carthageで\nプロダクトのディレクトリに`Cartfile` か `Cartfile.private`のファイルを作成し、下記の行を追加してください:\n\n```\ngithub \"cezheng/Fuzi\" ~\u003e 1.0.0\n```\nそして、下記のコマンドを実行してください:\n\n```\n$ carthage update\n```\n最後に、下記のようにXcodeのtargetを設定してください：\n\n1. ビルドターゲットの`General` -\u003e `Embedded Binaries`に、Carthageがビルドした`Fuzi.framework`を追加してください。\n2. `Build Settings`で`Search Paths`の`Header Search Paths`に`$(SDKROOT)/usr/include/libxml2`を追加してください。\n\n\n## 用例\n### XML\n```swift\nimport Fuzi\n\nlet xml = \"...\"\ndo {\n  // if encoding is omitted, it defaults to NSUTF8StringEncoding\n  let document = try XMLDocument(string: html, encoding: NSUTF8StringEncoding)\n  if let root = document.root {\n    print(root.tag)\n    \n    // define a prefix for a namespace\n    document.definePrefix(\"atom\", defaultNamespace: \"http://www.w3.org/2005/Atom\")\n    \n    // get first child element with given tag in namespace(optional)\n    print(root.firstChild(tag: \"title\", inNamespace: \"atom\"))\n\n    // iterate through all children\n    for element in root.children {\n      print(\"\\(index) \\(element.tag): \\(element.attributes)\")\n    }\n  }\n  // you can also use CSS selector against XMLDocument when you feels it makes sense\n} catch let error as XMLError {\n  switch error {\n  case .noError: print(\"wth this should not appear\")\n  case .parserFailure, .invalidData: print(error)\n  case .libXMLError(let code, let message):\n    print(\"libxml error code: \\(code), message: \\(message)\")\n  }\n}\n```\n### HTML\n`HTMLDocument` は `XMLDocument` サブクラス。\n\n```swift\nimport Fuzi\n\nlet html = \"\u003chtml\u003e...\u003c/html\u003e\"\ndo {\n  // if encoding is omitted, it defaults to NSUTF8StringEncoding\n  let doc = try HTMLDocument(string: html, encoding: NSUTF8StringEncoding)\n  \n  // CSS queries\n  if let elementById = doc.firstChild(css: \"#id\") {\n    print(elementById.stringValue)\n  }\n  for link in doc.css(\"a, link\") {\n      print(link.rawXML)\n      print(link[\"href\"])\n  }\n  \n  // XPath queries\n  if let firstAnchor = doc.firstChild(xpath: \"//body/a\") {\n    print(firstAnchor[\"href\"])\n  }\n  for script in doc.xpath(\"//head/script\") {\n    print(script[\"src\"])\n  }\n  \n  // Evaluate XPath functions\n  if let result = doc.eval(xpath: \"count(/*/a)\") {\n    print(\"anchor count : \\(result.doubleValue)\")\n  }\n  \n  // Convenient HTML methods\n  print(doc.title) // gets \u003ctitle\u003e's innerHTML in \u003chead\u003e\n  print(doc.head)  // gets \u003chead\u003e element\n  print(doc.body)  // gets \u003cbody\u003e element\n  \n} catch let error {\n  print(error)\n}\n```\n\n### エラー処理なんて、どうでもいい場合\n\n```swift\nimport Fuzi\n\nlet xml = \"...\"\n\n// Don't show me the errors, just don't crash\nif let doc1 = try? XMLDocument(string: xml) {\n  //...\n}\n\nlet html = \"\u003chtml\u003e...\u003c/html\u003e\"\n\n// I'm sure this won't crash\nlet doc2 = try! HTMLDocument(string: html)\n//...\n```\n\n### テキストノードを取得したい\nテキストノードだけではなく、全種類のノードは取得可能。\n\n```swift\nlet document = ...\n// すべてのエレメント、テキストとコメント子要素を取得する\ndocument.root?.childNodes(ofTypes: [.Element, .Text, .Comment])\n\n##Onoからの移行?\n下記2つのサンプルコードを見たら、`Ono`と`Fuzi`の違いをわかる。\n\n[Onoサンプル](https://github.com/mattt/Ono/blob/master/Example/main.m)\n\n[Fuziサンプル](FuziDemo/FuziDemo/main.swift)\n\n###子要素を取得\n**Ono**\n\n```objc\n[doc firstChildWithTag:tag inNamespace:namespace];\n[doc firstChildWithXPath:xpath];\n[doc firstChildWithXPath:css];\nfor (ONOXMLElement *element in parent.children) {\n  //...\n}\n[doc childrenWithTag:tag inNamespace:namespace];\n```\n**Fuzi**\n\n```swift\ndoc.firstChild(tag: tag, inNamespace: namespace)\ndoc.firstChild(xpath: xpath)\ndoc.firstChild(css: css)\nfor element in parent.children {\n  //...\n}\ndoc.children(tag: tag, inNamespace:namespace)\n```\n###クエリ結果を読み込む\n**Ono**\n\nObjective-Cの`NSFastEnumeration`。\n\n```objc\n// simply iterating through the results\n// mark `__unused` to unused params `idx` and `stop`\n[doc enumerateElementsWithXPath:xpath usingBlock:^(ONOXMLElement *element, __unused NSUInteger idx, __unused BOOL *stop) {\n  NSLog(@\"%@\", element);\n}];\n\n// stop the iteration at second element\n[doc enumerateElementsWithXPath:XPath usingBlock:^(ONOXMLElement *element, NSUInteger idx, BOOL *stop) {\n  *stop = (idx == 1);\n}];\n\n// getting element by index \nONOXMLDocument *nthElement = [(NSEnumerator*)[doc CSS:css] allObjects][n];\n\n// total element count\nNSUInteger count = [(NSEnumerator*)[document XPath:xpath] allObjects].count;\n```\n\n**Fuzi**\n\nSwift の `SequenceType` と `Indexable`。\n\n```swift\n// simply iterating through the results\n// no need to write the unused `idx` or `stop` params\nfor element in doc.xpath(xpath) {\n  print(element)\n}\n\n// stop the iteration at second element\nfor (index, element) in doc.xpath(xpath).enumerate() {\n  if idx == 1 {\n    break\n  }\n}\n\n// getting element by index \nif let nthElement = doc.css(css)[n] {\n  //...\n}\n\n// total element count\nlet count = doc.xpath(xpath).count\n```\n\n###XPath関数を評価する\n**Ono**\n\n```objc\nONOXPathFunctionResult *result = [doc functionResultByEvaluatingXPath:xpath];\nresult.boolValue;    //BOOL\nresult.numericValue; //double\nresult.stringValue;  //NSString\n```\n\n**Fuzi**\n\n```swift\nif let result = doc.eval(xpath: xpath) {\n  result.boolValue   //Bool\n  result.doubleValue //Double\n  result.stringValue //String\n}\n```\n## ライセンス\n\n`Fuzi` のオープンソースライセンスは MIT です。 詳しくはこちら [LICENSE](LICENSE) 。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcezheng%2FFuzi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcezheng%2FFuzi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcezheng%2FFuzi/lists"}