The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

yEd::Document - pure perl API to easily create yEd-loadable Documents from scratch (using XML::LibXML)

VERSION

Version 1.01

DEPENDENCIES

INTENTION

This package is intended to offer a way to create yEd Documents from scratch without having to deal with XML at all.

It is ment to help automating the task of creating graphical overviews of platforms, workflows, dependencies, ...

Since it doesn't support all the features of a yEd created Document you can only create Documents, loading Documents into the package is not supported, yet.

SUPPORTED FEATURES

This package and all available features have been developed and tested for yEd version 3.13.

If you find it doesn't work on another version or a specific platform, please let me know (see sections "BUGS" and/or "SUPPORT")).

Object features are supported as described at

and its subclasses.

The Document itself supports basic templating (section "TEMPLATING"), layers (section "LAYERS") and id management (section "OBJECT IDENTIFIERS").

You can also use relative coords for positioning your entities and use this feature for basic grouping (section "RELATIVE OBJECTS").

All entities are property based and can also be selected by properties (see yEd::PropertyBasedObject).

SYNOPSIS

This package provides a pure object oriented implementation, so only use functions and properties of yEd::Document and the other types in the context of a blessed instance.

Minimal example (creating an empty, yEd loadable Document):

    use yEd::Document;
    # create the document
    $d = yEd::Document->new();
    # build the document
    $xmlstring = $d->buildDocument();
    # or
    $d->buildDocument('/mypath/mydocument');

Example of different ways to create a Node with Label (all have the same effect on the Document):

    # the manual approach
    my $n = yEd::Node::ShapeNode->new('myid1');
    $n->x(50);
    $n->y(150);
    my $l = yEd::Label::NodeLabel->new('hello world');
    $n->addLabel($l);
    $doc->addNode($n);

    # a slightly more user friendly approach
    # provide the propertys with constructor and don't deal with IDs
    my $n = yEd::Node::ShapeNode->new($doc->getFreeId(), 'x' => 50, 'y' => 150);
    # directly add the label
    my $l = $n->addNewLabel('hello world');
    $doc->addNode($n);

    # or do it all in two lines
    my $n = $doc->addNewNode('ShapeNode', 'x' => 50, 'y' => 150);
    my $l = $n->addNewLabel('hello world');

    # or in one if you don't need the node ref (label ref is returned)
    my $l = $doc->addNewNode('ShapeNode', 'x' => 50, 'y' => 150)->addNewLabel('hello world');

    # or use templating if you need many copies of the same node
    my $l = $doc->addNewNodeTemplate('mytemplate', 'ShapeNode', 'x' => 50, 'y' => 150)->addNewLabel('hello world');
    my $n = $doc->addTemplateNode('mytemplate');
    # you can use $n to modify the copy (e.g. coords), you can also provide new properties with the call to addTemplateNode()
    # creating edges can be done in nearly the same ways

Example of using relative entities and layers (ready to run):

    use strict;
    use yEd::Document;
    
    my $d = yEd::Document->new();
    # play around with these values and note that the edge will always keep its right angles :)
    my $sx = -15; # -0.5 * default width 
    my $sy = 15; # 0.5 * default height -> lower left corner of source
    my $tx = 15; # 0.5 * default width 
    my $ty = 15; # 0.5 * default height -> lower right corner of target
    my $distance = 250;
    
    # place the absolute "root" node
    my $grouproot = $d->addNewNode('ShapeNode', 'x' => 1000, 'y' => 1000);
    # place another node $distance units to its right (or left if negative)
    my $n = $d->addNewNode('ShapeNode', 'x' => $distance, 'y' => 0, 'relative' => $grouproot);
    # place an edge on both which will go 50 units down, then $distance units (modified by anchor offsets) right/left (and then up again to connect to its target)
    my $e = $d->addNewEdge('PolyLineEdge', $grouproot, $n, 'relativeWaypoints' => 1, 'sx' => $sx, 'sy' => $sy, 'tx' => $tx, 'ty' => $ty);
    $e->waypoints([0,50],[$distance - $sx + $tx,0]);
    # place a circle on top of $grouproot to make the "group movement" visible in yEd
    my $c = $d->addNewNode('ShapeNode','shape' => 'ellipse', 'layer' => 1, 'x' => 1000, 'y' => 1000);
    $d->addNewEdge('PolyLineEdge', $n, $c, 'tArrow' => 'standard', 'sArrow' => 'standard');
    # you can now move the whole "group" by modifying $grouproot's x and y values (uncomment it and watch the difference in yEd)
    #$grouproot->setProperties('x' => 778.88, 'y' => 900);
    
    $d->buildDocument('test');

Example of using templating (ready to run):

    use strict;
    use yEd::Document;
    
    my $d = yEd::Document->new();
    
    # preparing the templates
    $d->addNewLabelTemplate('headline', 'NodeLabel', 'The house of Santa Claus', 'positionModell' => 'sandwich-n', 'fontSize' => 20);
    $d->addNewNodeTemplate('housenode', 'ShapeNode', 'shape' => 'ellipse', 'fillColor' => '#0000ff');
    my $wall = $d->addNewEdgeTemplate('wall', 'GenericEdge', 'lineWidth' => 5, 'fillColor' => '#0000ff', 'tArrow' => 'standard');
    $wall->addNewLabel('This', 'positionModell' => 'three_center-scentr', 'textColor' => '#005500', 'backgroundColor' => '#cccccc');
    $d->addEdgeTemplate('roof', $wall, 'fillColor' => '#ff0000');
    
    # adding the nodes
    my $n = $d->addTemplateNode('housenode', 'y' => 300);
    my $n1 = $d->addTemplateNode('housenode');
    my $n2 = $d->addTemplateNode('housenode', 'x' => 300);
    my $n3 = $d->addTemplateNode('housenode', 'x' => 300, 'y' => 300);
    # adding a node that wasn't defined as a template
    my $n4 = $d->addNewNode('ShapeNode', 'x' => 150, 'y' => -150, 'shape' => 'triangle', 'fillColor' => '#ff0000');
    $n4->addLabel($d->getTemplateLabel('headline'));
    
    # adding the edges
    $d->addTemplateEdge('wall',$n,$n1);
    ($d->addTemplateEdge('wall',$n1,$n2)->labels())[0]->text('is');
    ($d->addTemplateEdge('wall',$n2,$n)->labels())[0]->text('the');
    ($d->addTemplateEdge('wall',$n,$n3)->labels())[0]->text('house');
    ($d->addTemplateEdge('wall',$n3,$n2)->labels())[0]->text('of');
    ($d->addTemplateEdge('roof',$n2,$n4)->labels())[0]->text('San-');
    ($d->addTemplateEdge('roof',$n4,$n1)->labels())[0]->text('ta');
    ($d->addTemplateEdge('wall',$n1,$n3)->labels())[0]->text('Claus');
    
    $d->buildDocument('santa_claus');

OBJECT IDENTIFIERS

All Nodes and Edges of a Document must have an unique ID.

If you only use the yEd::Document's addNew...() functions and templating features you won't have to care for IDs.

But if you need to externally create Nodes or Edges from its classes you will have to provide the ID yourself.

In this case it is up to you to ensure unique values unless you obtain the IDs via yEd::Document's getFreeId() function.

This automatically created IDs will always be positive integer values, but if you provide your own IDs you can use almost anything.

If you load and save a Document in yEd all IDs will be converted to yEd's syntax ('n0','n1',...,'e0','e1',...).

TEMPLATING

If you have to add many copies of the same modification of a Node, Edge or Label have a look at yEd::Document's template functions (each with a 'Template' in its name).

These offer the ability to save an object's configuration and return and/or add copies of it.

For Nodes and Edges added Labels will be copied along with the template.

For Nodes that are relative to other Nodes you may want to call relative(0) or relative($newTarget) on the copy (or provide it with the properties parameter).

For Edges all waypoints are copied along with the template, this may not be what you want unless the Edge's relativeWaypoints property is set, consider calling clearWaypoints() on the copy.

Have a look at the 'Example of using templating' in the section "SYNOPSIS".

RELATIVE OBJECTS

A Node or Edge-waypoint by default will be absolute, this is its x and y values are directly applied to the drawing pane.

However you can change a Node to be relative to a given other Node by using the Node's relative property. In this case x and y are values that are added to the other Node's absolute position to determine the Node's position. The other Node however may be relative to yet another Node, too. Just make sure you don't create dependency loops. ;)

If you manually cut the relation of two Nodes by setting relative(0) on the dependend Node, the provided x and y value will not be changed but only interpreted as being absolute further on. If you want to cut the relation without changing the Node's current absolute position call $n->x($n->absX()) and $n->y($n->absY()) BEFORE the call to $n->relative(0).

Note that the x and y coords of a Node refer to its upper left corner or rather the upper left corner of the Node's surrounding rectangle (e.g. for ellipse ShapeNodes). Consider this if you do any Node positioning math in your scripts.

Edges do have such a property, too, it is called relativeWaypoints but is a boolean value in contrast to Node's property. If set to a true value any waypoints added to this Edge will be positioned relative to the previous waypoint. The first waypoint's position will be calculated relative to the Edge's anchor point on its source Node (sx,sy).

If you change from relativeWaypoints(1) to relativeWaypoints(0) there will be no conversion of the waypoint coords by default (same behavior as for Nodes).

Note that the source Node anchor point (sx,sy) is relative to the Node's center (sx = sy = 0) (as is true for the target anchor). This is somehow inconsistent as the Node's coords don't describe its center (you can obtain a Node's center by using its absCenter() function). Consider this if you do any positioning math in your scripts. However for relative waypoints you will likely have the desired bahavior by default, since first waypoint is relative to the anchor point which's absolute position is automatically computed for you by this package.

Have a look at the 'Example of using relative entities and layers' in the section "SYNOPSIS".

Tip: If you create "groups" with the reative feature always build your group on top of a root node that spans the whole area of the group. If you need the Nodes to not be surrounded by a background root Node simply make it invisible (no fill color, no border). This way you can always ask your root Node for the width and height of the whole "group" if you need these values for calculation. :)

Note that this way of "grouping" has no effect in yEd, it does only exist within the code.

LAYERS

yEd Documents / Nodes do only support "virtual" layering which is saved to the graphml file by giving the Nodes a special order (first Node defined is drawn first).

This concept has been adopted by this package. The layer is described as a property of each Node, named layer (Edges do not support layering, they will always be drawn on top the Nodes). Its default value is 0 which is the bottom layer. You can define the layer of a Node as any positive integer value, where a higher value is "more in front".

Within a single layer the drawing order of Nodes is undefined, if they overlap or need a special order because of other reasons use different layers.

Like with any other property you may obtain a list of all Nodes on a specified layer by using getNodesByProperties() (e.g. getNodesByProperties('layer' => 3).

Have a look at the 'Example of using relative entities and layers' in the section "SYNOPSIS".

SUBROUTINES/METHODS

new

Creates a new instance of yEd::Document and initializes it.

EXAMPLE

    my $doc = yEd::Document->new();

resetDocument

Resets (empties) and reinitializes this Document.

Previously registered templates will be kept.

EXAMPLE

    $doc->resetDocument();

buildDocument

Builds the Document and returns it as a string.

If a filename is provided (without the ending) it will additionally be written into filename.graphml .

EXAMPLE

    my $xml = $doc->buildDocument();
    my $xml = $doc->buildDocument('/path/to/mydoc');

getFreeId

Returns the next still free id, that can be used for creating new Nodes or Edges.

This is only required if you externally create new Nodes/Edges and you could also use own values as IDs (you will then have to ensure that all IDs are unique).

EXAMPLE

    my $myid = $doc->getFreeId();

getFrontLayer

Returns the highest layer that is set for any Node of this Document.

EXAMPLE

    my $front = $doc->getFrontLayer();

addNewLabelTemplate

Creates a template for Labels.

Must have parameters are: templatename (a string for accessing the template) , labeltype (Node- or EdgeLabel) , labeltext (the text for the Label)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The template Label is returned as a reference, if you modify this reference all further copies of the template will be affected ! Copies created earlier will not be affected since they are as said copies.

EXAMPLE

    my $tmplLabel = $doc->addNewLabelTemplate('mytemplate', 'NodeLabel', 'hello world', 'alignment' => 'left');

addLabelTemplate

Creates a template for Labels.

Must have parameters are: templatename (a string for accessing the template) , label (a reference to a Label object)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The source Label will not be changed, a copy of the Label will be used as template. If you want to modify the template after adding it use the returned reference to the copy.

EXAMPLE

    my $tmplLabel = $doc->addLabelTemplate('mytemplate', $srcLabel, 'text' => 'foo');

getTemplateLabel

Creates a copy of a previously created Label template and returns it.

Must have parameters are: templatename (a string for accessing the template)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

In contrast to Nodes and Edges Label templates can not be added directly because the need to be added to a Node or Edge. So use this function to obtain a copy and add it somewhere yourself.

EXAMPLE

    my $label = $doc->getTemplateLabel('mytemplate', 'text' => 'bar');

addNewNodeTemplate

Creates a template for Nodes.

Must have parameters are: templatename (a string for accessing the template) , nodetype (Shape- or GenericNode)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The template Node is returned as a reference, if you modify this reference all further copies of the template will be affected ! Copies created earlier will not be affected since they are as said copies.

EXAMPLE

    my $tmplNode = $doc->addNewNodeTemplate('mytemplate', 'ShapeNode', 'width' => 300, 'height' => 200);

addNodeTemplate

Creates a template for Nodes.

Must have parameters are: templatename (a string for accessing the template) , node (a reference to a Node object)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The source Node will not be changed, a copy of the Node will be used as template. If you want to modify the template after adding it use the returned reference to the copy.

EXAMPLE

    my $tmplNode = $doc->addNodeTemplate('mytemplate', $srcNode, 'width' => 300, 'height' => 200);

getTemplateNode

Creates a copy of a previously created Node template and returns it.

Must have parameters are: templatename (a string for accessing the template)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $node = $doc->getTemplateNode('mytemplate', 'x' => 50, 'y' => 200);

addTemplateNode

Creates a copy of a previously created Node template, adds it to the Document and returns it.

Must have parameters are: templatename (a string for accessing the template)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $node = $doc->addTemplateNode('mytemplate', 'x' => 50, 'y' => 200);

addNewEdgeTemplate

Creates a template for Edges.

Must have parameters are: templatename (a string for accessing the template) , edgetype (one of the supported Edge class names)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The template Edge is returned as a reference, if you modify this reference all further copies of the template will be affected ! Copies created earlier will not be affected since they are as said copies.

EXAMPLE

    my $tmplEdge = $doc->addNewEdgeTemplate('mytemplate', 'ArcEdge', 'tArrow' => 'standard');

addEdgeTemplate

Creates a template for Edges.

Must have parameters are: templatename (a string for accessing the template) , edge (a reference to an Edge object)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

The source Edge will not be changed, a copy of the Edge will be used as template. If you want to modify the template after adding it use the returned reference to the copy.

EXAMPLE

    my $tmplEdge = $doc->addEdgeTemplate('mytemplate', $srcEdge, 'tArrow' => 'standard');

getTemplateEdge

Creates a copy of a previously created Edge template and returns it.

Must have parameters are: templatename (a string for accessing the template), source, target (the new source and target yEd::Node refs for the new Edge)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $edge = $doc->getTemplateEdge('mytemplate', $srcNode, $trgNode, 'tArrow' => 'standard');

addTemplateEdge

Creates a copy of a previously created Edge template, adds it to the Document and returns it.

Must have parameters are: templatename (a string for accessing the template), source, target (the new source and target yEd::Node refs for the new Edge)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $edge = $doc->addTemplateEdge('mytemplate', $srcNode, $trgNode, 'tArrow' => 'standard');

addNewNode

Creates a new Node, adds it and returns a reference to it.

Must have parameters are: nodetype (Shape- or GenericNode)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $node = $doc->addNewNode('ShapeNode', 'x' => 60, 'y' => 450);

addNode

Takes a yEd::Node as parameter and adds it to the Document.

EXAMPLE

    $doc->addNode($node);

getNodes

Returns an array of all Nodes of this Document.

EXAMPLE

    my @nodes = $doc->getNodes();

getNodesByProperties

Takes arguments of the form property1 => value, property2 => value2, ....

Returns a list of all Nodes that matches the given filter.

EXAMPLE

    my @nodes = $doc->getNodesByProperties('width' => 300);

hasNodeId

Takes a Node's id as parameter and returns true if it is present in this Document.

EXAMPLE

    if ($doc->hasNodeId('myid1')) { ...

getNodeById

Takes an id as parameter and returns the Node with this id, if present in this Document.

EXAMPLE

    my $node = $doc->getNodeById('myid1');

removeNode

Takes a yEd::Node as parameter and tries to remove it from this document.

All connected Edges will be removed, too.

If there are Nodes relative to the given Node, they will also be removed (and their Edges and Nodes relative to these Nodes and so on, until all dependencies are resolved) unless the second (keepRelative) parameter is true. In this case the absolute x and y values are calculated and the relationship is cut, making the orphaned Nodes absolute.

EXAMPLE

    # in the "Example of using relative entities and layers" (see SYNOPSIS)
    # only the cirlce will remain if you call
    $d->removeNode($grouproot);
    # only $grouproot and $e will be removed if you call
    $d->removeNode($grouproot, 1);
    # $n will then be absolute at its last position

addNewEdge

Creates a new Edge, adds it and returns a reference to it.

Must have parameters are: edgetype (one of the supported Edge class names), source, target (the source and target yEd::Node refs for the new Edge)

Further parameters to set properties are optional (property1 => value, property2 => value2, ...).

EXAMPLE

    my $edge = $doc->addNewEdge('ArcEdge', $srcNode, $trgNode, 'tArrow' => 'standard');

addEdge

Takes a yEd::Edge as parameter and adds it to the Document.

EXAMPLE

    $doc->addEdge($edge);

getEdges

Returns an array of all Edges of this Document.

EXAMPLE

    my @edges = $doc->getEdges();

getEdgesByProperties

Takes arguments of the form property1 => value, property2 => value2, ....

Returns a list of all Edges that matches the given filter.

EXAMPLE

    my @edges = $doc->getEdgesByProperties('tArrow' => 'standard');

hasEdgeId

Takes an Edge's id as parameter and returns true if it is present in this Document.

EXAMPLE

    if ($doc->hasEdgeId('myid1')) { ...

getEdgeById

Takes an id as parameter and returns the Edge with this id, if present in this Document.

EXAMPLE

    my $edge = $doc->getEdgeById('myid1');

removeEdge

Takes a yEd::Edge as parameter and tries to remove it from this document.

EXAMPLE

    $doc->removeEdge($edge);

AUTHOR

Heiko Finzel, <heikofinzel at googlemail.com>

BUGS

Please report any bugs or feature requests to bug-yed-document at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=yEd-Document. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc yEd::Document

Also see perldoc of the other classes of this package.

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright 2014 Heiko Finzel.

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.