Difference between revisions of "Xml.pl"

From Organic Design wiki
m
 
(Updated)
Line 4: Line 4:
 
# - It cannot handle: Badly formed XML, CDATA sections
 
# - It cannot handle: Badly formed XML, CDATA sections
 
use strict;
 
use strict;
 +
  
 
# The XML is parse into a tree
 
# The XML is parse into a tree
Line 23: Line 24:
 
# - Includes hash of atts: /PATTERN/g returns a key,val list which can be treated as a hash
 
# - Includes hash of atts: /PATTERN/g returns a key,val list which can be treated as a hash
 
unless ($close) {
 
unless ($close) {
my $node = { '.name' => $name, $atts =~ /([-a-z0-9_:]+)\s*=\s*"(.*?)"/gi };
+
my $node = { -name => $name, $atts =~ /([-a-z0-9_:]+)\s*=\s*"(.*?)"/gi };
push @{$$ptr{'.content'}}, $node;      # Push the node onto the current content list
+
push @{$$ptr{-content}}, $node;      # Push the node onto the current content list
 
push @path, $ptr;                      # Move current focus into the new node
 
push @path, $ptr;                      # Move current focus into the new node
 
$ptr = $node;
 
$ptr = $node;
 
}
 
}
 
$ptr = pop @path if $close or $leaf;        # Move ptr up one level is </tag> or <tag/>
 
$ptr = pop @path if $close or $leaf;        # Move ptr up one level is </tag> or <tag/>
push @{$$ptr{'.content'}}, $text if $text;  # Add the after-node-content part to the current level
+
push @{$$ptr{-content}}, $text if $text;  # Add the after-node-content part to the current level
 
}
 
}
 
 
return $root;
 
return $root;
 
}
 
}
Line 41: Line 41:
 
my $indent;
 
my $indent;
 
$indent .= '  ' for 1..$level;
 
$indent .= '  ' for 1..$level;
my $name = $$ptr{'.name'};
+
my $xml = '';
print "$indent$name\n" if $name;
+
my $name = $$ptr{-name};
for ( @{$$ptr{'.content'}} ) {
+
$xml .= "$indent$name" if $name;
xmlBuild( $level+1, $_ ) if ref eq 'HASH';
+
for ( @{$$ptr{-content}} ) { $xml .= ref eq 'HASH' ? "\n".xmlBuild( $level+1, $_ ) : " => $_\n" }
}
+
return $xml;
 
}
 
}
 
 
# Test
 
xmlBuild 1, xmlParse '
 
<test>hello</test>
 
<properties a="1" b="1" >
 
content
 
<test2 b="eee"/>xxx
 
<properties a="1" b="1" >
 
content
 
<test2 b="eee"/>xxx
 
</properties>
 
</properties>
 
<associations a="1" b="ddd"/>
 
';
 

Revision as of 11:03, 30 January 2006

  1. !/usr/bin/perl
  2. A snipit for reading/writing nodal XML files
  3. - It can handle: Attributes, Mixed content
  4. - It cannot handle: Badly formed XML, CDATA sections

use strict;


  1. The XML is parse into a tree
  2. - each node in the tree is a hash of attributes plus .name and .content keys
  3. - each .content value is a ref to a list of ordered nodes/texts
  4. - only one root is allowed

sub xmlParse {

# First convert XML into a list split at every tag, ie. <tag> </tag> or <tag/> # - Each tag is five list items (first /, name, atts, second /, text between this and next) @_ = shift =~ /<\s*(\/?)([-a-z0-9_:]+)\s*(.*?)\s*(\/)?>\s*(.*?)\s*(?=<|$)/gi;

# Loop through all the tags and compile them into a tree my $ptr = my $root = {}; my @path = (); while ( $#_ >= 0 ) { my ( $close, $name, $atts, $leaf, $text ) = ( shift, shift, shift, shift, shift ); # Create a new node in the current content and update ptr if <tag/> or <tag> # - Includes hash of atts: /PATTERN/g returns a key,val list which can be treated as a hash unless ($close) { my $node = { -name => $name, $atts =~ /([-a-z0-9_:]+)\s*=\s*"(.*?)"/gi }; push @{$$ptr{-content}}, $node; # Push the node onto the current content list push @path, $ptr; # Move current focus into the new node $ptr = $node; } $ptr = pop @path if $close or $leaf; # Move ptr up one level is </tag> or <tag/> push @{$$ptr{-content}}, $text if $text; # Add the after-node-content part to the current level } return $root; }


  1. Construct XML text from passed hash tree

sub xmlBuild { my ($level, $ptr) = @_; my $indent; $indent .= ' ' for 1..$level; my $xml = ; my $name = $$ptr{-name}; $xml .= "$indent$name" if $name; for ( @{$$ptr{-content}} ) { $xml .= ref eq 'HASH' ? "\n".xmlBuild( $level+1, $_ ) : " => $_\n" } return $xml; }