{"id":17635927,"url":"https://github.com/mohawk2/xml-invisible","last_synced_at":"2025-07-12T20:34:16.116Z","repository":{"id":56837322,"uuid":"149924008","full_name":"mohawk2/xml-invisible","owner":"mohawk2","description":"Invisible XML implemented in Perl using Pegex","archived":false,"fork":false,"pushed_at":"2020-01-11T08:08:17.000Z","size":44,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-30T03:43:02.059Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mohawk2.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-22T21:55:26.000Z","updated_at":"2024-12-26T12:52:17.000Z","dependencies_parsed_at":"2022-09-09T21:10:37.565Z","dependency_job_id":null,"html_url":"https://github.com/mohawk2/xml-invisible","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/mohawk2/xml-invisible","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohawk2%2Fxml-invisible","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohawk2%2Fxml-invisible/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohawk2%2Fxml-invisible/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohawk2%2Fxml-invisible/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mohawk2","download_url":"https://codeload.github.com/mohawk2/xml-invisible/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mohawk2%2Fxml-invisible/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265049295,"owners_count":23703508,"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":[],"created_at":"2024-10-23T02:24:40.049Z","updated_at":"2025-07-12T20:34:16.053Z","avatar_url":"https://github.com/mohawk2.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nXML::Invisible - transform \"invisible XML\" documents into XML using a grammar\n\n# PROJECT STATUS\n\n| OS      |  Build status |\n|:-------:|--------------:|\n| Linux   | [![Build Status](https://travis-ci.org/mohawk2/xml-invisible.svg?branch=master)](https://travis-ci.org/mohawk2/xml-invisible) |\n\n[![CPAN version](https://badge.fury.io/pl/XML-Invisible.svg)](https://metacpan.org/pod/XML::Invisible) [![Coverage Status](https://coveralls.io/repos/github/mohawk2/xml-invisible/badge.svg?branch=master)](https://coveralls.io/github/mohawk2/xml-invisible?branch=master)\n\n# SYNOPSIS\n\n    use XML::Invisible qw(make_parser);\n    my $transformer = make_parser(from_file($ixmlspec));\n    my $ast = $transformer-\u003e(from_file($ixml_input));\n\n    use XML::Invisible qw(make_parser ast2xml);\n    my $transformer = make_parser(from_file($ixmlspec));\n    my $xmldoc = ast2xml($transformer-\u003e(from_file($ixml_input)));\n    to_file($outputfile, $xmldoc-\u003etoStringC14N(1));\n\n    # or, with conventional pre-compiled Pegex grammar\n    my $parser = Pegex::Parser-\u003enew(\n      grammar =\u003e My::Thing::Grammar-\u003enew,\n      receiver =\u003e XML::Invisible::Receiver-\u003enew,\n    );\n    my $got = $parser-\u003eparse($input);\n\n    # from command line\n    cpanm XML::Invisible XML::Twig\n    perl -MXML::Invisible=make_parser,ast2xml -e \\\n      'print ast2xml(make_parser(join \"\", \u003c\u003e)-\u003e(\"(a+b)\"))-\u003etoStringC14N(1)' \\\n      examples/arith-grammar.ixml | xml_pp\n\n    # canonicalise a document\n    use XML::Invisible qw(make_parser make_canonicaliser);\n    my $ixml_grammar = from_file('examples/arith-grammar.ixml');\n    my $transformer = make_parser($ixml_grammar);\n    my $ast = $transformer-\u003e(from_file($ixml_input));\n    my $canonicaliser = make_canonicaliser($ixml_grammar);\n    my $canonical = $canonicaliser-\u003e($ast);\n\n# DESCRIPTION\n\nAn implementation of Steven Pemberton's Invisible XML concept, using\n[Pegex](https://metacpan.org/pod/Pegex). Supply it with your grammar, in Pegex format (slightly\ndifferent from Steven's specification due to differences between his\nnotation and Pegex's), it returns you a function, which you can call to\ntransform \"invisible XML\" documents into actual XML.\n\nThis is largely a Pegex \"receiver\" class that exploits the `+` and `-`\nsyntax in rules in slightly unintended ways, and a wrapper to make\nthis operate.\n\n# GRAMMAR SYNTAX\n\nSee [Pegex::Syntax](https://metacpan.org/pod/Pegex::Syntax). Generally, all rules will result in an XML\nelement. All terminals will need to capture with `()` (see example\nbelow).\n\nHowever, if you specify a dependent token with `+` it will\ninstead become an attribute (equivalent of Steven's `@`). If `-`,\nthis will \"flatten\" (equivalent of Steven's `-`) - the children will\nbe included without making an element of that node. Since in Pegex any\nelement can be skipped entirely with `.`, you can use that instead of\n`-` to omit terminals.\n\nE.g.\n\n    expr: +open -arith +close\n    open: /( LPAREN )/\n    close: /( RPAREN )/\n    arith: left -op right\n    left: +name\n    right: -name\n    name: /(a)/ | /(b)/\n    op: +sign\n    sign: /( PLUS )/\n\nWhen given `(a+b)` yields:\n\n    \u003cexpr open=\"(\" sign=\"+\" close=\")\"\u003e\n      \u003cleft name=\"a\"/\u003e\n      \u003cright\u003eb\u003c/right\u003e\n    \u003c/expr\u003e\n\n# FUNCTIONS\n\n## make\\_parser\n\nExportable. Returns a function that when called with an \"invisible XML\"\ndocument, it will return an abstract syntax tree (AST), of the general form:\n\n    {\n      nodename =\u003e 'expr',\n      attributes =\u003e { open =\u003e '(', sign =\u003e '+', close =\u003e ')' },\n      children =\u003e [\n        { nodename =\u003e 'left', attributes =\u003e { name =\u003e 'a' } },\n        { nodename =\u003e 'right', children =\u003e [ 'b' ] },\n      ],\n    }\n\nArguments:\n\n- an \"invisible XML\" Pegex grammar specification, OR a [Pegex::Grammar](https://metacpan.org/pod/Pegex::Grammar) object\n\nSee [XML::Invisible::Receiver](https://metacpan.org/pod/XML::Invisible::Receiver) for more.\n\n## ast2xml\n\nExportable. Turns an AST, as output by [\"make\\_parser\"](#make_parser),\nfrom [XML::Invisible::Receiver](https://metacpan.org/pod/XML::Invisible::Receiver) into an object of class\n[XML::LibXML::Document](https://metacpan.org/pod/XML::LibXML::Document). Needs [XML::LibXML](https://metacpan.org/pod/XML::LibXML) installed, which as of\nversion 0.05 of this module is only a suggested dependency, not required.\n\nArguments:\n\n- an AST from [XML::Invisible::Receiver](https://metacpan.org/pod/XML::Invisible::Receiver)\n\n## make\\_canonicaliser\n\nExportable. Returns a function that when called with an AST as produced\nfrom a document by a [\"make\\_parser\"](#make_parser), returns a canonical version of\nthe original document, or `undef` if it failed.\n\nArguments:\n\n- an XML::Invisible grammar\n\nIt uses a few heuristics:\n\n- literals that are 0-1 (`?`) or any number (`*`) will be omitted\n- literals that are at least one (`+`) will be inserted once\n- if an \"any\" group is given, the first one that matches will be selected\n\n    This last one means that if you want a canonical representation that is\n    not the bare minimum, provide that as a literal first choice (see the\n    `assign` rule below - while it will accept any or no whitespace, the\n    \"canonical\" version is given):\n\n        expr: target .assign source\n        target: +name\n        assign: ' = ' | (- EQUAL -)\n        source: -name\n        name: /( ALPHA (: ALPHA | DIGIT )* )/\n\n# DEBUGGING\n\nTo debug, set environment variable `XML_INVISIBLE_DEBUG` to a true value.\n\n# SEE ALSO\n\n[Pegex](https://metacpan.org/pod/Pegex)\n\n[https://homepages.cwi.nl/~steven/ixml/](https://homepages.cwi.nl/~steven/ixml/) - Steven Pemberton's Invisible XML page\n\n# AUTHOR\n\nEd J, `\u003cetj at cpan.org\u003e`\n\n# BUGS\n\nPlease report any bugs or feature requests on\n[https://github.com/mohawk2/xml-invisible/issues](https://github.com/mohawk2/xml-invisible/issues).\n\nOr, if you prefer email and/or RT: to `bug-xml-invisible\nat rt.cpan.org`, or through the web interface at\n[http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XML-Invisible](http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XML-Invisible). I will be\nnotified, and then you'll automatically be notified of progress on your\nbug as I make changes.\n\n# LICENSE AND COPYRIGHT\n\nCopyright 2018 Ed J.\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the the Artistic License (2.0). You may obtain a\ncopy of the full license at:\n\n[http://www.perlfoundation.org/artistic\\_license\\_2\\_0](http://www.perlfoundation.org/artistic_license_2_0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohawk2%2Fxml-invisible","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmohawk2%2Fxml-invisible","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohawk2%2Fxml-invisible/lists"}