{"id":14966029,"url":"https://github.com/raku-community-modules/xml","last_synced_at":"2025-04-10T02:22:00.242Z","repository":{"id":1070741,"uuid":"911464","full_name":"raku-community-modules/XML","owner":"raku-community-modules","description":"An Object-Oriented XML Library for Raku","archived":false,"fork":false,"pushed_at":"2025-02-26T19:14:14.000Z","size":240,"stargazers_count":29,"open_issues_count":10,"forks_count":26,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-03T00:04:30.872Z","etag":null,"topics":["parser","raku","xml"],"latest_commit_sha":null,"homepage":"https://raku.land/zef:raku-community-modules/XML","language":"Raku","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"artistic-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raku-community-modules.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","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":"2010-09-15T01:29:54.000Z","updated_at":"2025-02-21T09:57:33.000Z","dependencies_parsed_at":"2025-02-20T12:22:23.056Z","dependency_job_id":"641d47b1-4462-4688-a9db-3b020d5184bb","html_url":"https://github.com/raku-community-modules/XML","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raku-community-modules%2FXML","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raku-community-modules%2FXML/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raku-community-modules%2FXML/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raku-community-modules%2FXML/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raku-community-modules","download_url":"https://codeload.github.com/raku-community-modules/XML/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248143163,"owners_count":21054719,"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":["parser","raku","xml"],"created_at":"2024-09-24T13:35:43.583Z","updated_at":"2025-04-10T02:22:00.194Z","avatar_url":"https://github.com/raku-community-modules.png","language":"Raku","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Actions Status](https://github.com/raku-community-modules/XML/actions/workflows/linux.yml/badge.svg)](https://github.com/raku-community-modules/XML/actions) [![Actions Status](https://github.com/raku-community-modules/XML/actions/workflows/macos.yml/badge.svg)](https://github.com/raku-community-modules/XML/actions) [![Actions Status](https://github.com/raku-community-modules/XML/actions/workflows/windows.yml/badge.svg)](https://github.com/raku-community-modules/XML/actions)\n\nAn Object-Oriented XML Framework for Raku\n=========================================\n\nIntroduction\n------------\n\nXML (originally called Exemel) is a full fledged XML library for Raku.\n\nIt handles parsing, generating, manipulating and querying XML. It supports element queries, parent element information, namespaces, and an extendable interface.\n\nIt supports every major kind of XML Node (XML::Node):\n\n    * Document (XML::Document)\n\n    * Element (XML::Element)\n\n    * Text (XML::Text)\n\n    * Comment (XML::Comment)\n\n    * PI (XML::PI)\n\n    * CDATA (XML::CDATA)\n\nYou can easily serialize the objects back to XML text by using any XML::Node object in a string context.\n\nDocumentation\n-------------\n\n### XML\n\nA *module* that provides a few simple subroutines.\n\n#### from-xml(Str $string --\u003e XML::Document)\n\nParse the string as XML, and return an XML::Document object.\n\n#### from-xml-stream(IO $input --\u003e XML::Document)\n\nSlurp the IO, parse the contents, and return an XML::Document object.\n\n#### from-xml-file(IO::Path() $file --\u003e XML::Document)\n\nReturn an XML::Document object representing the specified file. You will be able to call $xml.save(); to save back to the original file.\n\n#### open-xml(Str|IO::Path|IO::Handle $src)\n\nA multi sub that picks the right way to open `$src` . If a `Str` is given it defaults to a filename. If such file is found it assumes a `Str` containing XML.\n\n#### make-xml(Str $name, ... --\u003e XML::Element)\n\nSee the *XML::Element.craft()* function for details on how this works.\n\n### XML::Node\n\nA *role* used by the rest of the XML Node classes.\n\n#### $.parent [rw]\n\nThe XML::Element or XML::Document to which this Node belongs. Only an XML::Document will have an undefined *$.parent* property.\n\n#### remove()\n\nRemoves the Node from its parent element.\n\n#### reparent(XML::Element $newparent)\n\nRemoves the Node from its existing parent (if any) and sets the specified node as its *$.parent* property.\n\n#### previousSibling()\n\nReturns the Node that exists in the parent just before this one. Returns Nil if there is none.\n\n#### nextSibling()\n\nReturns the Node that exists in the parent just after this one. Returns Nil if there is none.\n\n#### cloneNode()\n\nThis is a polymorphic method that exists in all XML::Node objects, and does what is needed to return a clone of the desired Node.\n\n#### ownerDocument()\n\nReturns the top-level XML::Document that this Node belongs to.\n\n### XML::Document [XML::Node]\n\nA Node representing an XML document. You can use array access syntax on it to access children of the root node. You can use hash access syntax on it to access attributes of the root node.\n\n#### $.version\n\nThe XML version. Default: '1.0'\n\n#### $.encoding\n\nThe text encoding, if specified in the XML declarator.\n\n#### %.doctype\n\nHas two keys, *'type'* represents the document type, *'value'* represents the rest of the DOCTYPE declaration (if applicable.)\n\n#### $.root\n\nThe root XML::Element of the document. This also proxies many of the useful XML::Element methods, so that they can be called directly from the XML::Document object.\n\n#### $.filename\n\nIf an XML::Document represents a file on the file-system, this is the path to that file.\n\n#### new(Str $xml, :$filename)\n\nParse the passed XML and return an XML::Document. If the *$filename* variable is passed, the *$.filename* property will be set on the object.\n\n#### new(XML::Element $root)\n\nCreate a new XML::Document object, with the specified XML::Element as its root element.\n\n#### load(Str $filename)\n\nCreate a new XML::Document object, representing the specified file. The *$.filename* property will be set.\n\n#### save(Str $filename?, Bool :$copy)\n\nSave the XML back into a file. If the *$filename* parameter is not passed, we use the *$.filename* property (if it is set, otherwise we return False.)\n\nIf the *:copy* option is true, we don't re-set the *$.filename* property.\n\n#### .elems()\n\nSee XML::Element.elems() for details, but this basically tells you how many child nodes (whether Element nodes or otherwise) the root node has. \n\n### XML::Element [XML::Node]\n\nA Node representing an individual XML element. You can use array access syntax to access child nodes, and hash access syntax to access or set attributes.\n\n#### $.name [rw]\n\nThe tag name of the element.\n\n#### @.nodes\n\nAny child nodes that may exist. All members of *@.nodes* MUST be an object that does the XML::Node role.\n\nUnless you are doing something that requires direct access of the *@.nodes* property, it's probably easier (and less noisy) to use the array access syntax.\n\n#### %.attribs\n\nXML attributes for the current node. We expect the keys and values to be strings, but you can use numeric values if you want. Remember on emitting or parsing, all values will be strings, even if you set it as a number.\n\nIt is recommended that you do not use *%.attribs* directly to set values. Use the *set()* method or the hash access syntax to set attribute values, and use the *unset()* method to delete attributes.\n\n#### $.idattr [rw, default: 'id']\n\nSpecifies what attribute will be used as the XML Id when using the *getElementById()* method. This defaults to *'id'* which is used in (X)HTML and thus the most common.\n\n#### new(Str $xml)\n\nReturn a new XML::Element object representing the specified XML string.\n\n#### insert(XML::Node $node)\n\nInsert an XML::Node at the beginning of our *@.nodes* list.\n\n#### insert(Str $name, ...)\n\nCreate a new XML::Element with the given name, and insert it to the beginning of our nodes list. Uses *craft()* to build the element.\n\nAny named parameters will be used as attributes, any positional parameters will be used as child nodes.\n\nPositional parameters can be one of the following:\n\n    * An XML::Node object. Will be added as is.\n\n    * A String. Will be included as an XML::Text node.\n\n    * A Capture. Calls *craft()* using the Capture as the signature.\n\n    * Anything else, will be stringified, and added as an XML::Text node.\n\n#### append(XML::Node $node)\n\nAppend an XML::Node to the bottom of our *@.nodes* list.\n\n#### append(Str $name, ...)\n\nSee _insert (Str $name, ...)_ but at the bottom.\n\n#### before(XML::Node $existing, XML::Node $new)\n\nInsert the *$new* Node before the *$existing* Node. It only works if the *$existing* node is actually found in our *@.nodes* list.\n\n#### before(XML::Node $node)\n\nOnly works if our *$.parent* is an XML::Element. Inserts the Node before the current one.\n\n#### before(Str $name, ...)\n\nSee _insert (Str $name, ...)_ and _before(XML::Node $node)_ and figure it out.\n\n#### after(XML::Node $existing, XML::Node $new)\n\nLike _before($existing, $new)_ but put the node after the _$existing_ one.\n\n#### after(XML::Node $node)\n\nLike _before(XML::Node $node)_ but put the node after the current one.\n\n#### after(Str $name, ...)\n\nAs per the others.\n\n#### insert-xml(Str $xml)\n\nInsert to top, a new XML::Element representing the given XML string.\n\n#### append-xml(Str $xml)\n\nAppend to bottom, a new XML::Element representing the given XML string.\n\n#### before-xml(Str $xml)\n\nInsert a new XML::Element for the XML string, before the current element.\n\n#### after-xml(Str $xml)\n\nInsert a new XML::Element for the XML string, after the current element.\n\n#### insertBefore(XML::Node $new, XML::Node $existing)\n\nAn alternative to _before($existing, $new)_ using DOM semantics.\n\n#### insertAfter(XML::Node $new, XML::Node $existing)\n\nAn alternative to _after($existing, $new)_ using DOM-like semantics.\n\n#### replace(XML::Node $existing, XML::Node $new)\n\nIf the *$existing* node is found, replace it with *$new* , otherwise, we return False.\n\n#### replaceChild(XML::Node $new, XML::Node $existing)\n\nAn alternative to *replace()* with DOM semantics.\n\n#### removeChild (XML::Node $node)\n\nRemoves the *$node* from our child *@.nodes* if it exists. If it doesn't we return False.\n\n#### firstChild()\n\nReturn our first child node.\n\n#### lastChild()\n\nReturn our last child node.\n\n#### index-of($find)\n\nPass it a smart match rule, and it will return array index of the first matching node.\n\n#### craft(Str $name, ...)\n\nCreate and return a new XML::Element object with the given name. Named and positional parameters are handled as with _insert(Str $name, ...)_\n\n#### set(Str $name, $value)\n\nSet an attribute with the given *$name* to the specified *$value* . If the *$value* is a Str or Numeric is is added directly. If it is Bool and True, the value will be set to the same as the *$name* . If it is Bool and False, the attribute will be deleted.\n\nAny other value will be stringified using the *.Str* method.\n\n#### set(...)\n\nA *set()* call containing no positional paramters, will pass all named parameters to the above *set()* as key/value pairs.\n\n#### unset($name, ...)\n\nEach positional parameter passed will be assumed to be the name of an attribute to delete.\n\n#### unset(:$name, ...)\n\nWe assume the key of each named parameter passed to be the name of an attribute to delete. The value means absolutely nothing and is in fact ignored entirely.\n\n#### is-bool($attrib)\n\nReturns True if the given attribute exists, and has the same value as its name (the definition of an XML boolean.)\n\n#### add-values (Str $attrib, Set $values)\n\nFor the attribute with the given *$name* , perform the set-wise union, *(|)* , of the set of *$values* passed to the method and the existing values of the attribute. The results are converted back to a string value and stored in the attribute. For example:\n\n```perl\nmy $xml = from-xml('\u003ctest\u003e\u003cfolks we = \"Al Barb Carl\"/\u003e\u003c/test\u003e');\nsay $xml[0]; # \u003cfolks we=\"Al Barb Carl\"/\u003e\n\n$xml[0].add-values(\"we\", \u003cCarl Dave Ellie\u003e.Set);\nsay $xml[0]; # \u003cfolks we=\"Al Barb Carl Dave Ellie\"/\u003e\n```\n\n#### delete-values (Str $attrib, Set $values)\n\nFor the attribute with the given *$name* , perform the set-wise difference, *(-)* , of the existing values of the attribute and the *$values* passed to the method. The results are converted back to a string value and stored in the attribute. For example:\n\n```perl\nmy $xml = from-xml('\u003ctest\u003e\u003cfolks we = \"Al Barb Carl Dave Ellie\"/\u003e\u003c/test\u003e');\nsay $xml[0]; # \u003cfolks we=\"Al Barb Carl Dave Ellie\"/\u003e\n\n$xml[0].delete-values(\"we\", \u003cAl Ellie Zack\u003e.Set);\nsay $xml[0]; # \u003cfolks we=\"Barb Carl Dave\"/\u003e\n```\n\n#### test-values (Str $attrib, @tests)\n\nFor the attribute with the given *$name* , test each value in @tests for membership in the set of existing values of the attribute. Returns a hash that has the test values as keys and the boolean results of the membership test as values. For example:\n\n```perl\nmy $xml = from-xml('\u003ctest\u003e\u003cfolks we = \"Barb Carl Dave\"/\u003e\u003c/test\u003e');\nsay $xml[0]; # \u003cfolks we=\"Barb Carl Dave\"/\u003e\n\nmy %test-results = $xml[0].test-values(\"we\", \u003cAl Carl Zack\u003e.Array);\nsay %test-results; # \"Al\" =\u003e Bool::False, \"Carl\" =\u003e Bool::True, \"Zack\" =\u003e Bool::False\n```\n\n#### elements()\n\nReturn all child XML::Elements.\n\n#### elements(...)\n\nSpecify a query of named parameters. Special processing parameters are used:\n\n    * TAG\n\nIf set, elements must match the given tag name.\n\n    * NS\n\nIf set, elements must match the given namespace prefix.\n\n    * URI\n\nIf set, elements must match the given namespace URI.\n\n    * RECURSE\n\nIf set to a non-zero digit, child elements will also be searched for elements matching the queries. The recursion will traverse a tree depth of the value set to this parameter.\n\n    * NEST\n\nUsed with *RECURSE* if this is set to True, this will recurse even child elements that matched the query.\n\n    * SINGLE\n\nIf this is set to True, we will return the first matched value. If no values match, we will return False. If *SINGLE* is not specified, or is set to False, we return an Array of all matches (this may be empty if no nodes matched.)\n\n    * OBJECT\n\nIf this is set to True, instead of returning an Array of results, we will return a XML::Element object with the same name as the original input object, with its nodes set to the matched elements.\n\n    * POS\n\nIf set to an Int, the element must be the nth child to match. If set to a Range, the element's position must be within the range. If set to a Whatever match rule (e.g. * \u003e 2) the rule must match.\n\nIf this is set to an Int, and RECURSE is not a positive value, then the SINGLE rule will be set to True.\n\n    * NOTPOS\n\nSet to an Int, then we match if the element is not the nth child.\n\n    * FIRST\n\nMatch only if the element is the first child.\n\nIf RECURSE is not a positive value, then SINGLE will be set to True.\n\n    * !FIRST\n\nDon't include the first child in the results.\n\n    * LAST\n\nMatch only if the element is the last child.\n\nIf RECURSE is not a positive value, then SINGLE will be set to True.\n\n    * !LAST\n\nDon't include the last child in the results.\n\n    * EVEN\n\nMatch even child nodes. By default this is based on natural position (i.e. the second child element is even) see BYINDEX for details.\n\n    * ODD\n\nMatch odd child nodes. By default this is based on natural position (i.e. the first child element is odd) see BYINDEX for details.\n\n    * BYINDEX\n\nIf set to True, then the EVEN and ODD rules match against the array index value rather than the natural position. Therefore, the first element will be even, since it is in position 0.\n\nAny other named paramters not in the above list, will be assumed to be attributes that must match. You can match by value, regular expression, or whatever code matches.\n\n```perl\n  my $head = $html.elements(:TAG\u003chead\u003e, :SINGLE);\n  my @stylesheets = $head.elements(:TAG\u003clink\u003e, :rel\u003cstylesheet\u003e);\n  my @middle = $table.elements(:!FIRST, :!LAST);\n  my @not-red = $div.elements(:class(* ne 'red'));\n  my @elms-by-class-name = $html.elements(:RECURSE(Inf), :class('your-class-name')); # find all elements by class name\n```\n\n#### lookfor(...)\n\nA shortcut for elements(..., :RECURSE)\n\n#### getElementById($id)\n\nReturn the XML::Element with the given id.\n\n#### getElementsByTagName($name, :$object?)\n\nReturn an array of XML::Elements with the given tag name.\n\nIf the boolean $object named parameter is true, then the 'OBJECT' rule will be applied to the query sent to elements().\n\n#### nsPrefix(Str $uri)\n\nReturn the XML Namespace prefix.\n\nIf no prefix is found, it returns an undefined value. If the URI is the default namespace, it returns ''.\n\n#### nsURI(Str $prefix?)\n\nReturns the URI associated with a given XML Namespace prefix. If the *$prefix* is not specified, return the default namespace.\n\nReturns an undefined value if there is no XML Namespace URI assigned.\n\n#### setNamespace($uri, $prefix?)\n\nAssociated the given XML Namespace prefix with the given URI. If no *$prefix* is specified, it sets the default Namespace.\n\n#### comments()\n\nReturn an array of all XML::Comment child nodes.\n\n#### cdata()\n\nReturns an array of all XML::CDATA child nodes.\n\n#### instructions()\n\nReturns an array of all XML::PI child nodes.\n\n#### contents()\n\nReturns an array of all XML::Text child nodes.\n\n#### .elems()\n\nXML and Raku have quite different meanings for the word \"element\". In XML, an Element is a \u003ctag/\u003e, whereas in Raku, it's a single element in a one-dimensional list/array. \n\nThe TL;DR is that .elements() uses the XML meaning, whereas .elems() uses the Raku meaning. \n\nThe slightly longer version is that, since XML::Element does Positional, it has to have a .elems() method that supports the Raku meaning. So .elems will tell you how many children the node has, not the number of XML::Element children (since there will likely be some text nodes and things in there as well). \n\n### XML::Text [XML::Node]\n\nA Node representing a portion of plain text.\n\n#### $.text\n\nThe raw text, with no whitespace chopped out.\n\n#### Str(XML::Entity :$decode, Bool :$min, Bool :$strip, Bool :$chomp, Bool :numeric)\n\nReturn the text, with various modifications depending on what was passed. If :decode is set, we decode XML entities using the XML::Entity object. If :min is set, we replace multiple whitespace characters with a single space. If :strip is set, we trim off leading and trailing whitespace. If :chomp is set, we remove the trailing newline. The :numeric value is passed to the decoder specified in :decode.\n\n#### string(XML::Entity $decode=XML::Entity.new)\n\nAn alias for Str(:$decode, :min, :strip, :chomp, :numeric);\n\nBasically, make the text node easier to read for humans.\n\nThe default $decode value is a new instance of XML::Entity.\n\n### XML::Comment [XML::Node]\n\nRepresents an XML Comment\n\n```xml\n  \u003c!-- comment here --\u003e\n```\n\n#### $.data\n\nContains the string data of the content.\n\n### XML::PI [XML::Node]\n\nRepresents an XML processing instruction.\n\n```xml\n  \u003c?blort?\u003e\n```\n\n#### $.data\n\nContains the string text of the processing instruction.\n\n### XML::CDATA [XML::Node]\n\nRepresents an XML CDATA structure.\n\n```xml\n  \u003c![CDATA[ random cdata content here ]]\u003e\n```\n\n#### $.data\n\nContains the string text of the CDATA.\n\n### XML::Entity\n\n#### decode(Str $input, Bool :$numeric)\n\nDecode XML entities found in the string.\n\n#### encode(Str $input, Bool :$hex, ...)\n\nEncode known XML entities, plus any numeric values passed as extra parameters. Any additional parameters should be the regular base10 integer values of the additional characters that should be encoded.\n\nIf :hex is true we encode using hexidecimal entities instead of decimal.\n\n#### add (Str $name, Str $value)\n\nAdd a new custom entity named $name with the replacement value $value.\n\n#### add (Pair $pair)\n\nAn alias for self.add($pair.key, $pair.value);\n\nExamples\n--------\n\nA quick example, for more, see the tests in the 't/' folder.\n\n### test.xml\n\n```xml\n\u003ctest\u003e\n  \u003cgreeting en=\"hello\"\u003eworld\u003c/greeting\u003e\n  \u003cfor\u003e\n    \u003citem\u003eYes\u003c/item\u003e\n    \u003citem\u003eNo\u003c/item\u003e\n    \u003citem\u003eMaybe\u003c/item\u003e\n    \u003citem\u003eWho cares?\u003c/item\u003e\n  \u003c/for\u003e\n\u003c/test\u003e\n```\n\n### test.raku\n\n```raku\nuse XML;\n\nmy $xml = from-xml-file('test.xml');\n\nsay $xml[1]\u003cen\u003e ~ $xml[1][0]; ## \"hello world\"\nsay $xml[3][5][0]; ## \"Maybe\"\n\n$xml[3].append('item', 'Never mind');\n\nsay $xml[3][9]; ## \u003citem\u003eNever mind\u003c/item\u003e\n```\n\nAuthor\n------\n\nTimothy Totten, supernovus on #raku, https://github.com/supernovus/\n\n### Note\n\nThe XML::Grammar library was originally based on the now defunct [XML::Grammar::Document](http://github.com/krunen/xml) library, but modified to work with Rakudo 'ng' and later 'nom', with other changes specific to this library.\n\nLicense\n-------\n\n[Artistic License 2.0](http://www.perlfoundation.org/artistic_license_2_0)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraku-community-modules%2Fxml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraku-community-modules%2Fxml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraku-community-modules%2Fxml/lists"}