XML::M...ocument(3pm)

πŸ“¦
version 1.38 Β· 3 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ¦‹ NAME πŸ¦‹

XML::Mini::Document β€” a Perl implementation of the XML::Mini Document API. That's the whole intro, short and iconic. ✨

This one lives in the User Contributed Perl Documentation section of your friendly neighborhood (3pm) man pages. πŸ’…


✨ SYNOPSIS ✨

Okay bestie, deep breath, here's the whole tour in one shot β€” parsing first, then creating. It's giving "tutorial but make it fashion." πŸ’–

use XML::Mini::Document;

use Data::Dumper;

###### PARSING XML #######

# create a new object
my $xmlDoc = XML::Mini::Document->new();

# init the doc from an XML string
$xmlDoc->parse($XMLString);

# You may use the toHash() method to automatically
# convert the XML into a hash reference
my $xmlHash = $xmlDoc->toHash();

print Dumper($xmlHash);

# You can also manipulate the elements like directly, like this:

# Fetch the ROOT element for the document
# (an instance of XML::Mini::Element)
my $xmlRoot = $xmlDoc->getRoot();

# play with the element and its children
# ...
my $topLevelChildren = $xmlRoot->getAllChildren();

foreach my $childElement (@{$topLevelChildren})
{
    # ...
}

###### CREATING XML #######

# Create a new document from scratch

my $newDoc = XML::Mini::Document->new();

# This can be done easily by using a hash:
my $h = {
 'spy'  => {
    'id'    => '007',
    'type'  => 'SuperSpy',
    'name'  => 'James Bond',
    'email' => 'mi5@london.uk',
    'address'    => 'Wherever he is needed most',
    },
};

$newDoc->fromHash($h);

# Or new XML can also be created by manipulating
#elements directly:

my $newDocRoot = $newDoc->getRoot();

# create the <? xml ?> header
my $xmlHeader = $newDocRoot->header('xml');
# add the version
$xmlHeader->attribute('version', '1.0');

my $person = $newDocRoot->createChild('person');

my $name = $person->createChild('name');
$name->createChild('first')->text('John');
$name->createChild('last')->text('Doe');

my $eyes = $person->createChild('eyes');
$eyes->attribute('color', 'blue');
$eyes->attribute('number', 2);

# output the document
print $newDoc->toString();

This example would output :

<?xml version="1.0"?>
 <person>
  <name>
   <first>
    John
   </first>
   <last>
    Doe
   </last>
 </name>
 <eyes color="blue" number="2" />
 </person>

πŸ’– DESCRIPTION πŸ’–

So, XML::Mini::Document is the programmer's handle to XML::Mini functionality. It's the class you actually talk to. The main character. πŸ‘‘

Every single program that uses XML::Mini creates one of these instances. With your XML::Mini::Document object you can reach the root XML::Mini::Element, find / fetch / create elements, and read in or output XML strings. That's the whole job description and she does it flawlessly. πŸ¦‹


🌸 new [XMLSTRING]

Creates a shiny new instance of XML::Mini::Document. And if you hand it that optional XMLSTRING, it'll call fromString with it for you β€” two birds, zero effort, we love an auto-pilot queen. 🫢

🌸 getRoot

Returns a reference to this document's root element (an instance of XML::Mini::Element). Boom. That's your entry point to everything.

🌸 setRoot NEWROOT

Sets the document root to the NEWROOT XML::Mini::Element object. Simple, clean, no notes. ✨

🌸 isElement ELEMENT

Returns a true value if ELEMENT is an instance of XML::Mini::Element, and a false one otherwise. It's a vibe check, but for classes. πŸ’…

🌸 isNode NODE

Returns a true value if NODE is an instance of XML::MiniNode, and false otherwise. (Yes β€” XML::MiniNode, no :: in the middle there. That's its actual name, not a typo, stay calm. πŸ’€)

🌸 createElement NAME [VALUE]

Creates a brand new XML::Mini::Element going by the name NAME.

⚠️ Careful babes: this element is an orphan β€” it has no assigned parent and it will be lost unless you append it somewhere (via XML::Mini::Element::appendChild()) at some point. Don't just leave it floating there in the void. πŸ™ˆ

If you pass the optional VALUE parameter (string or numeric), the new element's text / numeric content gets set to VALUE. Returns a reference to the newly created element. Slay. πŸ”₯

🌸 getElement NAME [POSITON]

Searches the document for an element named NAME.

Returns a reference to the first XML::Mini::Element named NAME if it finds one, and NULL otherwise.

NOTE: the search runs like this, and the first element that matches wins:

  • Check the Root Element's immediate children (in order) for a match. πŸ”
  • Ask each immediate child (in order) to XML::Mini::Element::getElement() β€” so each child then proceeds similarly: checking all its immediate children in order, and then asking them to getElement(). Recursion girlies, we love it. 🌈

If you pass a numeric POSITION parameter, getElement() will return only the POSITIONth element named NAME (starting at 1). So, on this document:

<?xml version="1.0"?>
<people>
 <person>
  bob
 </person>
 <person>
  jane
 </person>
 <person>
  ralph
 </person>
</people>

$people->getElement('person') will return the element containing the text node 'bob', while $people->getElement('person', 3) will return the element containing the text 'ralph'. Math but make it cute. ✨

🌸 getElementByPath PATH [POSITIONARRAY]

Attempts to return a reference to the (first) element at PATH, where PATH is the path through the structure, going from the root element all the way to the element you're asking for.

For example, in the document represented by:

<partRateRequest>
 <vendor>
  <accessid user="myusername" password="mypassword" />
 </vendor>
 <partList>
  <partNum>
   DA42
  </partNum>
  <partNum>
   D99983FFF
  </partNum>
  <partNum>
   ss-839uent
  </partNum>
 </partList>
</partRateRequest>
$accessid = $xmlDocument->getElementByPath('partRateRequest/vendor/accessid');

will return exactly what you expect β€” the accessid element with the attributes user = "myusername" and password = "mypassword". Chef's kiss. πŸ’‹

BUT be careful, bestie:

my $accessid = $xmlDocument->getElementByPath('partRateRequest/partList/partNum');

will return the partNum element with the value "DA42". To get at the other partNum elements you've gotta either use the POSITIONSARRAY, or use the getAllChildren() method on the partRateRequest element. There is no third option, don't ask.

POSITIONSARRAY functions just like the POSITION parameter to getElement(), except instead of giving the position of a single element, you have to indicate the position of all the elements in the path. So to grab the third part number element, you'd go:

my $thirdPart = $xmlDocument->getElementByPath('partRateRequest/partList/partNum', 1, 1, 3);

Those extra 1,1,3 parameters are saying: you want to retrieve the 1st partRateRequest element in the document, the 1st partList child of partRateRequest, and the 3rd partNum child of the partList element β€” which in this case is the partNum element containing 'ss-839uent'. πŸŽ€

Returns the XML::Mini::Element reference if found, and NULL otherwise.

🌸 parse SOURCE

Initialises the XML::Mini::Document (and its root XML::Mini::Element) using the XML from the file SOURCE.

SOURCE can also be a string containing your XML document.

And listen β€” on top of parsing strings, the other possible SOURCEs are:

# a file location string
$miniXMLDoc->parse('/path/to/file.xml');

# an open file handle
open(INFILE, '/path/to/file.xml');
$miniXMLDoc->parse(*INFILE);

# an open FileHandle object
my $fhObj = FileHandle->new();
$fhObj->open('/path/to/file.xml');
$miniXML->parse($fhObj);

In every single case where SOURCE is a file or a file handle, XML::Mini takes care of slurping the contents and closing the handle for you. So thoughtful, so considerate, genuinely the moment. πŸ§šπŸ’–

🌸 fromHash HASHREF [OPTIONS]

Parses a "hash representation" of your XML structure. For each key => value pair inside that hash ref, XML::Mini will create an element named 'key':

  • with the text contents set to 'value', if 'value' is a string ✨
  • one for each element of 'value', if 'value' is an ARRAY REFERENCE πŸŽ€
  • with suitable children for each subkey => subvalue, if 'value' is a HASH REFERENCE πŸ’–

For instance, if fromHash() gets passed a simple hash ref like:

my $h = {

 'spy'  => {
    'id'    => '007',
    'type'  => 'SuperSpy',
    'name'  => 'James Bond',
    'email' => 'mi5@london.uk',
    'address'    => 'Wherever he is needed most',
    },
};

then:

$xmlDoc->fromHash($h);
print $xmlDoc->toString();

will output

<spy>
 <email> mi5@london.uk </email>
 <name> James Bond </name>
 <address> Wherever he is needed most </address>
 <type> SuperSpy </type>
 <id> 007 </id>
</spy>

The optional OPTIONS parameter can be used to specify which keys to use as attributes (instead of creating subelements). For example, calling

my $options = {
            'attributes'    => {
                    'spy'   => 'id',
                    'email' => 'type',
                    'friend' => ['name', 'age'],
                }
        };

my $h = {

    'spy'  => {
        'id'    => '007',
        'type'  => 'SuperSpy',
        'name'  => 'James Bond',
        'email' => {
                'type'          => 'private',
                '-content'      => 'mi5@london.uk',

            },
        'address' => {
                'type'  => 'residential',
                '-content' => 'Wherever he is needed most',
            },

        'friend' => [
                {
                    'name'  => 'claudia',
                    'age'   => 25,
                    'type'  => 'close',
                },

                {
                    'name'  => 'monneypenny',
                    'age'   => '40something',
                    'type'  => 'tease',
                },

                {
                    'name'  => 'Q',
                    'age'   => '10E4',
                    'type'  => 'pain',
                }
            ],

    },
};
$xmlDoc->fromHash($h, $options);
print $xmlDoc->toString();

will output something like:

✨ and here's that whole example in its full glory ✨

<spy id="007">
 <name> James Bond </name>
 <email type="private"> mi5@london.uk </email>
 <address>
  <type> residential </type>
  Wherever he is needed most
 </address>
 <type> SuperSpy </type>
 <friend age="25" name="claudia">
  <type> close </type>
 </friend>
 <friend age="40something" name="monneypenny">
  <type> tease </type>
 </friend>
 <friend age="10E4" name="Q">
  <type> pain </type>
 </friend>
</spy>

so yeah, like the example is showing you πŸ‘† you can use the optional href to say which tags should get attributes made for them instead of elements, and you can also nest hash refs and array refs inside each other to build out really complicated structures. go off πŸ’…

NOTE: the second you use a hash reference, you lose the order the elements were in 😭. only array references (which make a list of same-named elements) can keep their order. that's just how she goes.

See ALSO: the docs for the related toHash() method 🫢

Still TODO: ngl, someone should write better docs for this! πŸ™ˆ for now you can go peek inside the test suite in the source distribution β€” that's where the real tea is.


🧚 fromString XMLSTRING

boots up the XML::Mini::Document (and its root XML::Mini::Element) using the XML string XMLSTRING. ✨

Returns the number of immediate children the root XML::Mini::Element has now, bestie.

πŸŽ€ fromFile FILENAME

boots up the XML::Mini::Document (and its root XML::Mini::Element) using the XML from the file FILNAME. πŸ“

Returns the number of immediate children the root XML::Mini::Element has now.

🌸 toString [DEPTH]

turns this XML::Mini::Document object into a string and hands it back to you. πŸ’–

the optional DEPTH can be passed in to set the space offset for the first element.

if the optional DEPTH is set to $XML::Mini::NoWhiteSpaces, then no \n and no whitespace gets inserted into the xml string at all β€” it's literally all on one single line, no spaces between the tags. periodt.

Returns a string of XML representing the document.

πŸ¦‹ toFile FILENAME [SAFE]

stringifies the XML document and saves it to the file FILENAME. πŸ’Ύ

if the SAFE flag is passed and it's a true value, toFile does some extra checking and will refuse to open the file if the filename matches either of these:

m|/\.\./|
m|#;`\*|

or if FILENAME points to a softlink. also, if SAFE is 'NOOVERWRITE', then toFile will fail if the FILENAME already exists. no clobbering, no cap 🫢

πŸ‘‘ toHash

transforms the XML structure that's internally represented inside the object (whether you built it manually or parsed it from a file or a string) into a HASH reference, and returns that href. πŸ†

so like, if this XML gets parse()d:

<people>

 <person id="007">
  <email> mi5@london.uk </email>
  <name> James Bond </name>
  <address> Wherever he is needed most </address>
  <type> SuperSpy </type>
 </person>

 <person id="006" number="6">
  <comment> I am not a man, I am a free number </comment>
  <name> Number 6 </name>
  <email type="private"> prisoner@aol.com </email>
  <address> 6 Prison Island Road, Prison Island, Somewhere </address>
 </person>

</people>

the hash reference you get back is gonna look exactly like this (this is the output from Data::Dumper):

'people' => {

     'person' => [
                   {
                     'email' => 'mi5@london.uk',
                     'name' => 'James Bond',
                     'type' => 'SuperSpy',
                     'address' => 'Wherever he is needed most',
                     'id' => '007'
                   },
                   {
                     'email' => {
                                  'type' => 'private',
                                  '-content' => 'prisoner@aol.com'
                                },
                     'comment' => 'I am not a man, I am a free number',
                     'number' => '6',
                     'name' => 'Number 6',
                     'address' => '6 Prison Island Road, Prison Island, Somewhere',
                     'id' => '006'
                   }
                 ]
   }

look at that structure 😭 she's beautiful.

⭐ getValue

a lil utility function β€” it just calls the root XML::Mini::Element's getValue(). easy peasy.

πŸ’€ dump

a debugging aid πŸ› β€” dump returns a nicely formatted dump of the current structure of the XML::Mini::Document object. chef's kiss for when you're confused.


😭 CAVEATS 😭

you literally cannot parse "cross-nested" tags with regular expressions β€” like sequences of the form <a><b><a>...</a></b></a>. that's just not a thing regex can do, bestie.

BUT 🫢 if you have the Text::Balanced module installed (it comes installed by default with Perl 5.8), then those sequences get handled flawlessly. slay.

even if you don't have Text::Balanced available, you can still generate this type of XML just fine β€” the problem only shows up when you're parsing. generating is giving, parsing is not πŸ’€


πŸ‘‘ AUTHOR πŸ‘‘

Copyright (C) 2002-2008 Patrick Deegan, Psychogenic Inc.

programs that use this code are bound to the terms and conditions of the GNU GPL (see the LICENSE file). if you wanna include these modules in non-GPL code, you need prior written authorisation from the authors. that's not optional, periodt.

this library is released under the terms of the GNU GPL version 3, which makes it available only for free programs ("free" here is being used in the GPL sense, see http://www.gnu.org for more details). anyone wishing to use this library inside a proprietary or otherwise non-GPLed program MUST contact psychogenic.com to acquire a distinct license for their application. this approach encourages the use of free software while still allowing for proprietary solutions that support further development. iconic behavior tbh 🌈

πŸŽ€ LICENSE πŸŽ€

XML::Mini::Document module, part of the XML::Mini XML parser/generator package.
Copyright (C) 2002-2008 Patrick Deegan
All rights reserved

XML::Mini is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

XML::Mini is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with XML::Mini.  If not, see <http://www.gnu.org/licenses/>.

πŸ’– SEE ALSO πŸ’–


and that's a wrap bestie πŸŽ€ this whole thing is perl v5.36.0, dated 2022-10-15, from the XML::M...ocument(3pm) man page β€” go forth and parse some XML, you've got this πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from