-
Notifications
You must be signed in to change notification settings - Fork 326
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cookbook XML\n\nRecreate PR #2121 from https://github.com/ocaml/ocaml…
- Loading branch information
Cuihtlauac ALVARADO
committed
May 13, 2024
1 parent
2f496c7
commit caebf2b
Showing
3 changed files
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
packages: | ||
- name: "ezxmlm" | ||
tested_version: "1.1.0" | ||
used_libraries: | ||
- ezxmlm | ||
discussion: | | ||
- **Understanding `ezxmlm`:** The `ezxmlm` package provides high level functions that can be used to parse and generate an XML file. This package is based on `xmlm` which which works with element start/end callbacks. | ||
- **Alternatives:** TODO | ||
--- | ||
|
||
(* Lets take a simple structure: a pair list representing an ID and an associated text *) | ||
|
||
let item_list = [ ("1", "Text 1"); ("2", "Text 2")] | ||
|
||
(* We will convert each item into an XML node. Each XML node must have one of the form: | ||
- \`Data text | ||
- \`El ((("","tag"), attribute_list), node_list) | ||
The attribute_list must have the form [("", "name"), "value"); ...] | ||
Then we can type: | ||
*) | ||
|
||
let item_nodes = item_list |> List.map (fun (id, text) -> | ||
`El ((("","item"), [("","id"), id]), [ `Data text ])) | ||
|
||
(* We can enclose these items in a list element *) | ||
|
||
let list_node = `El ((("","list"), []), item_nodes) | ||
|
||
(* Then create and export the XML tree, in a string or in a file *) | ||
|
||
let xml_string = Ezxmlm.to_string [list_node] | ||
|
||
let xml_header = {xml|<?xml version="1.0" encoding="utf-8"?>|xml} | ||
let () = | ||
Out_channel.with_open_bin "file.xml" | ||
(fun oc -> Ezxmlm.to_channel oc (Some xml_header) [list_node]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--- | ||
packages: | ||
- name: "ezxmlm" | ||
tested_version: "1.1.0" | ||
used_libraries: | ||
- ezxmlm | ||
discussion: | | ||
- **Understanding `ezxmlm`:** The `ezxmlm` package provides high level functions that can be used to parse and generate an XML file. This package is based on `xmlm` which which works with element start/end callbacks. | ||
- **Alternatives:** TODO | ||
--- | ||
|
||
(* Lets take a simple XML string. *) | ||
|
||
let xml_string = | ||
{xml|<?xml version="1.0" encoding="utf-8"?> | ||
<root> | ||
<list> | ||
<item id="1" class="a">text 1</item> | ||
<item id="2" class="a">text 2</item> | ||
<item id="3" class="b">text 3</item> | ||
</list> | ||
</root>|xml} | ||
|
||
(* Let's parse it: *) | ||
|
||
let (_dtd, xml_node) = Ezxmlm.from_string xml_string | ||
|
||
(* Or if the XML is in a file.xml *) | ||
|
||
let (_dtd, xml_node) = In_channel.with_open_bin | ||
"file.xml" Ezxmlm.from_channel | ||
|
||
(* Fetching a member by its tag, assuming it is unique, can be done by the `member` function. (Note: an exception is raised in UTop by the pretty printer; however, these values are correct) *) | ||
|
||
let root_node = Ezxmlm.member "root" xml_node | ||
let list_node = Ezxmlm.member "list" root_node | ||
|
||
(* Fetching all members by their tags returning a list of nodes can be done by the `members` function *) | ||
|
||
let item_node_list = Ezxmlm.members "item" list_node | ||
|
||
(* We can then fetch the enclosed text *) | ||
|
||
let data_list = List.map Ezxmlm.data_to_string item_node_list | ||
|
||
(* If we want to filter with the attributes, we have to deal with a list of pairs (attribute list, nodes) which are returned by `members_with_attr`. *) | ||
|
||
let item_pair_list = Ezxmlm.members_with_attr "item" list_node | ||
let item_pair = Ezxmlm.filter_attr "id" "2" item_pair_list | ||
|
||
(* We can get its attribute values or use the node with other functions. *) | ||
|
||
let class_ = Ezxmlm.get_attr "class" (fst item_pair) | ||
let data = Ezxmlm.data_to_string (snd item_pair) | ||
|
||
(* If we expect the attribute selection not to be unique, the `filter_attrs` should be used instead of `filter_attr`. *) | ||
|
||
let item_pair_list' = Ezxmlm.filter_attrs "class" "a" item_pair_list | ||
let data_list = List.map | ||
(fun item_pair -> Ezxmlm.data_to_string (snd item_pair)) | ||
item_pair_list' | ||
|
||
(* A whole example: an RSS parser that returns a list of pair (title, link) from an RSS string *) | ||
|
||
let parse_rss str = | ||
let open Ezxmlm in | ||
let (_dtd,xml) = from_string str in | ||
xml | ||
|> member "rss" | ||
|> member "channel" | ||
|> members "item" | ||
|> List.map begin fun item -> | ||
let title = (item | ||
|> member "title" | ||
|> data_to_string) | ||
and link = (item | ||
|> member "link" | ||
|> data_to_string) | ||
in | ||
(title, link) | ||
end |