pharo-graphics / Bloc

Low-level UI infrastructure & framework for Pharo
MIT License
80 stars 39 forks source link

Rewrite SVG parser avoiding creation of intermediate XML nodes? (being more SAX2-like) #526

Open tinchodias opened 2 months ago

tinchodias commented 2 months ago

In short, the XMLParser project provides tests and examples to read XML without creating a XMLnode instance for each read node. As a reference, see subclasses of SAX2ElementHandler in 'XML-Parser-Tests'.


Right now, when we want to get BlElements from a SVG string, something like this is the first step: XMLDOMParser parse: '<svg ........ </svg>'. The parser (in 'XML-Parser' package), outputs a BlElement that might be in fact a tree of elements. My question is not about the output, but about what happens in the middle to create it: The "dom" that the parser returns is "visited" by the Bloc's BlSvgFactory.

The factory will execute this method on each SVG's node:

readElementFrom: aXMLNode
    | symbol |
    aXMLNode
        splitStyleAttribute;
        inheritAttributes.

    symbol := (aXMLNode name asString , 'From:') asSymbol.

    ^ (self respondsTo: symbol)
        ifTrue: [ self perform: symbol with: aXMLNode ]
        ifFalse: [ self metadataFrom: aXMLNode ]

that will send a message according to the name of the svg's element that is being read (e.g. rect, circle, path, g). That method will then read the attributes by querying each XML node like this:

positionFrom: node on: aBlElement
    | x y |
    x := y := 0.
    node
        attributeAt: 'x'
        ifPresent: [ :value | x := value asNumber ].
    node
        attributeAt: 'y'
        ifPresent: [ :value | y := value asNumber ].
    aBlElement position: x @ y

EDIT: As an example, parsing the classical tiger creates a DOM with 1200 nodes.

tinchodias commented 2 months ago

For the record, this might be a starting point to evaluate this issue/idea:

  1. Create BlSvgHandler as a subclass of SAX2ContentHandler
  2. Override startElement: aQualifiedName attributes: anAttributeDictionary with a halt or trace.
  3. Put some svg code in svgString variable and run:
    parser := SAX2Parser on: svgString.
    handler := BlSvgHandler new.
    parser contentHandler: handler.
    parser parseDocument