You can create a node using
constructor to parse the node. Or you can initialize node
contents by parsing it using
However, these both approaches require you to
first prepare appropriate
instance and a list of read node names.
There are comfortable routines like
that take care of this for you. They create appropriate lexer,
and may create also suitable
TStream instance to read
given file content.
Some details about parsing:
Our VRML/X3D lexer is a unified lexer for both VRML 1.0, 2.0 and (classic) X3D. Most of the syntax is identical, minor differences can be handled correctly by a lexer because it always knows VRML/X3D header line of the given file. So it knows what syntax to expect.
VRML/X3D version of the original file is saved in
TVRMLRootNode.ForceVersion. This will be used later when saving. Parser always returns
TVRMLRootNodeinstance, this keeps some per-file settings like version and X3D profile, components and meta values.
When saving, you can save any
TVRMLNodeinstance to file. If it is not
TVRMLRootNode, or if
TVRMLRootNode.HasForceVersionis false, we simply assume it uses the latest X3D version.
In engine versions <= 2.5.0 we experimented with auto-detecting the suitable VRML/X3D version for nodes inside, but this mechanism was dropped. It was complicated, and was failing anyway for complicated cases (nodes from mixed versions, things with routes, imports, exports etc.). If you want to save a specific VRML/X3D version, it's best to simply wrap it inside
TVRMLRootNodeand force desired version explicitly. Modern programs should target only X3D anyway, as VRML 1.0 is ancient, and VRML 2.0 is old too (from 1997).
ForVRMLVersionmethod mentioned earlier may be used to decide which node classes to create based on VRML/X3D version indicated in the file's header line.
To properly handle DEF / USE mechanism we keep a list of known node names while parsing. After a node with
DEFclause is parsed we add the node name and it's reference to
NodeNameBindinglist that is passed through all parse routines. When a
USEclause is encountered, we just search this list for appropriate node name.
Simple VRML rules of
USEbehavior make this approach correct. Remember that VRML name scope is not modeled after normal programming languages, where name scope of an identifier is usually limited to the structure (function, class, etc.) where this identifier is declared. In VRML, name scope always spans to the end of whole VRML file (or to the next
DEFoccurrence with the same name, that overrides previous name). Also, the name scope is always limited to the current file — for example, you cannot use names defined in other VRML files (that you included by
Inlinenodes, or that include you). (Prototypes and external prototypes in VRML 2.0 are designed to allow reusing VRML code between different VRML files.)
The simple trick with adding our name to
NodeNameBindingafter the node is fully parsed prevents creating loops in our graph, in case supplied VRML file is invalid.