Cannot parse text elements

40 views
Skip to first unread message

frank.h...@gmail.com

unread,
Jul 13, 2020, 10:39:06 AM7/13/20
to SVG++ library
Hi @ll,

I've tried to add text handling to my application but I cannot get it work. This is what I did (as instructed by the documentation):

Created a class TextContext derived from the BaseContext class


class TextContext : public BaseContext
{
......
    template<class Range>
    void set_text(Range const & text);
}



I also added specialized factory (In my case text elements are always children of a group node):

template<>
struct ChildContextFactories::apply<GroupContext, svgpp::tag::element::text>
//struct ChildContextFactories::apply<BaseContext, svgpp::tag::element::text>
{
    typedef svgpp::factory::context::on_stack_with_mutable_xml_element<TextContext> type;
};



and added adapted to processed_elements:

struct processed_elements_t
.....

    svgpp::tag::element::text>



Unfortunately when compiling the compiler complains:

Severity    Code    Description    Project    File    Line    Suppression State
Error    C2039    'set_text': is not a member of 'LayoutContext::BaseContext'    NetLister    d:\_proj\netlister\external\svgpp\include\svgpp\policy\text_events.hpp    19   


Can someone help me? I have no clue what I'm missing. Why it set_text missing in the base_context?

Best regards,
Frank

svgpp

unread,
Jul 13, 2020, 12:02:44 PM7/13/20
to SVG++ library
Hi Frank,

Probably you have BaseContext created for <text> element in some cases due to ChildContextFactories complex logic. 
You may try adding something like "void foo() {static_assert(!std::is_same<ElementTag, svgpp::tag::element::text>::value);}" to each ChildContextFactories::apply that returns BaseContext and have element tag as template argument. This way you will see how it was instantiated.

Regards
Oleg

frank.h...@gmail.com

unread,
Jul 13, 2020, 4:16:23 PM7/13/20
to SVG++ library

Hi Oleg,

thanks for taking your time.
I commented out/disabled all factories except this one:

struct ChildContextFactories
{
    template<class ParentContext, class ElementTag, class Enable = void>
    struct apply
    {
        // Default definition handles "svg" and "g" elements
        typedef svgpp::factory::context::on_stack_with_mutable_xml_element<BaseContext> type;



        void foo() { static_assert(!std::is_same<ElementTag, svgpp::tag::element::text>::value); }

    };
};

Unfortunately this didn't help (set_text still missing in BaseContext) and the static_assert also doesn't fire.

Any other suggestions how I can track this down?


I've attached a link to the header containing the factories... just in case you want to take a look at it?


https://www.dropbox.com/s/5gtskc4rjsx9h4z/ChipLayoutContext.h?dl=0



Thanks,

Frank

svgpp

unread,
Jul 13, 2020, 5:29:47 PM7/13/20
to SVG++ library
I've looked through your header. Side note - I doubt that you need BaseContext in ChildContextFactories at all. <g> and <svg> are GroupContext, shapes have their own contexts. Root of SVG file is always <svg> so you may pass GroupContext to svgpp document_traversal::load_document.
Also I suggest to remove definition of first "apply" leaving declaration. All cases should be handled by specializations below.
In commented out apply's you are returning BaseContext for <svg> and <g> that are children of GroupContext. Why do you handle them such way, shouldn't <svg> and <g> always be GroupContext?

frank.h...@gmail.com

unread,
Jul 14, 2020, 3:48:45 AM7/14/20
to SVG++ library
Hi Oleg,
thanks for your help! It compiles correctly now and both

void set(svgpp::tag::attribute::x, Range const& range);
void set(svgpp::tag::attribute::y, Range const& range);


in my class TextContext are called. Unfortunately this one is NOT called at all:

void set_text(Range const& text);

I thought it might be a problem that the texts are nested in <tspan> nodes so I added:

template<>
struct ChildContextFactories::apply<TextContext, svgpp::tag::element::tspan>
{
    typedef svgpp::factory::context::on_stack_with_mutable_xml_element<TextContext> type;
};


and I tried this with two different text nodes (one with tspan and one without)...:

        <text
             id="text15421-8"
             y="888"
             x="666">TEST1<tspan
                 y="12350.531"
                 x="11325.469"
                 id="tspan15443">P7</tspan>TEST2</text>
        <text
             id="text-test3"
             y="12350.438"
             x="12401.906">TEST3</text>

... but no luck!

Is there anything else I need to consider in order to get set_text called? And why will the inner <tspan> context created BEFORE the surrounding <text>? Is this intentional?

/Frank

svgpp

unread,
Jul 14, 2020, 4:22:58 AM7/14/20
to SVG++ library
Hi Frank,

No idea so far. What XML parser do you use? May be the problem is in particular XML parser policy.
You may try setting breakpoint at https://github.com/svgpp/svgpp/blob/master/include/svgpp/document_traversal.hpp#L239 to see if text handling function is called.

About "why will the inner <tspan> context created BEFORE the surrounding <text>" it shouldn't be possible. Child context is always created with parent context passed as constructor parameter.

Regards
Oleg

frank.h...@gmail.com

unread,
Jul 14, 2020, 4:37:54 AM7/14/20
to SVG++ library
Hi Oleg,

I'm using rapid_xml_ns. I've debugged document traversal.

The line:

if (xml_policy_t::is_text(xml_child_element))
.....

is only called ONE* time with the <tspan> as xml_child_element which returns false.
*(I don't reach the breakpoint for <text> nodes).

Shouldn't this return true for <tspan>?

Regards,
Frank

frank.h...@gmail.com

unread,
Jul 14, 2020, 5:20:42 AM7/14/20
to SVG++ library
Hi again!

I digged a little deeper. It looks like there's possible a bug in SVGPP or rapid_xml_ns:

rapid_xml_ns doesn't know about text nodes (text nodes are standard nodes in rapid_xml):

    enum node_type
    {
        node_document,      //!< A document node. Name and value are empty.
        node_element,       //!< An element node. Name contains element name. Value contains text of first data node.
        node_data,          //!< A data node. Name is empty. Value contains data text.
        node_cdata,         //!< A CDATA node. Name is empty. Value contains data text.
        node_comment,       //!< A comment node. Name is empty. Value contains comment text.
        node_declaration,   //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
        node_doctype,       //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
        node_pi             //!< A PI node. Name contains target. Value contains instructions.
    };

but other xml parsers know about text nodes (e.g. xerces):

enum  NodeType{
  ELEMENT_NODE = 1, ATTRIBUTE_NODE = 2, TEXT_NODE = 3, CDATA_SECTION_NODE = 4,
  ENTITY_REFERENCE_NODE = 5, ENTITY_NODE = 6, PROCESSING_INSTRUCTION_NODE = 7, COMMENT_NODE = 8,
  DOCUMENT_NODE = 9, DOCUMENT_TYPE_NODE = 10, DOCUMENT_FRAGMENT_NODE = 11, NOTATION_NODE = 12
}


Question is: Can the be solved with rapidxml somehow?

regards,
Frank

svgpp

unread,
Jul 14, 2020, 5:38:15 AM7/14/20
to SVG++ library
Text nodes are rapidxml_ns::node_data and should be handled well. Can it be that you pass "parse_no_data_nodes" as template flag to rapidxml_ns::xml_document::parse?

frank.h...@gmail.com

unread,
Jul 14, 2020, 5:52:59 AM7/14/20
to SVG++ library
Indeed.... that was it. Now it's working as expected!

Thanks alot for your help!
Frank
Reply all
Reply to author
Forward
0 new messages