在wxWidgets

时间:2017-08-18 09:46:02

标签: c++ xml wxwidgets libxml2

我正在编写一个派生自wxStyledTextCtrl的类,我想让它美化给定的XML而不添加除空格之外的任何内容。我找不到简单的工作方案。我只能使用wxStyledTextCtrl,wxXmlDocument和libxml2。

我的目标是在使用包含以下文本的wxString调用SetText之后

<!-- comment1 --> <!-- comment2 --> <node><emptynode/> <othernode>value</othernode></node>

控件应显示

<!-- comment1 -->
<!-- comment2 -->
<node>
    <emptynode/>
    <othernode>value</othernode>
</node>

使用libxml2我设法几乎实现了这一点,但它也打印了XML声明(例如<?xml version="1.0" encoding="UTF-8"?>),我不想这样做。

inb4,我正在寻找简单而干净的解决方案 - 我不想手动删除第一行格式化的XML

使用给定的工具是否有任何简单的解决方案?我觉得我错过了什么。

1 个答案:

答案 0 :(得分:0)

有简单的解决方案吗?不。但是如果你想写自己漂亮的打印功能,你基本上需要在xml文档树上进行深度优先迭代,然后随时打印。有一点轻微的复杂性,你还需要一些知道何时关闭标签的方法。

这是使用wxWidgets xml类完成此操作的一种方法的不完整示例。目前,它不处理属性,自闭元素(例如示例文本中的'')或任何其他特殊元素类型。一个完整漂亮的打印机需要添加这些东西。

#include <stack>
#include <set>
#include <wx/xml/xml.h>
#include <wx/sstream.h>

wxString PrettyPrint(const wxString& in)
{
    wxStringInputStream string_stream(in);
    wxXmlDocument doc(string_stream);
    wxString pretty_print;

    if (doc.IsOk())
    {
        std::stack<wxXmlNode*> nodes_in_progress;
        std::set<wxXmlNode*> visited_nodes;

        nodes_in_progress.push(doc.GetDocumentNode());

        while (!nodes_in_progress.empty())
        {
            wxXmlNode* cur_node = nodes_in_progress.top();
            nodes_in_progress.pop();
            int depth = cur_node->GetDepth();

            for (int i=1;i<depth;++i)
            {
                pretty_print << "\t";
            }

            if (visited_nodes.find(cur_node)!=visited_nodes.end())
            {
                pretty_print << "</" << cur_node->GetName() << ">\n";
            }
            else if ( !cur_node->GetNodeContent().IsEmpty() )
            {
                //If the node has content, just print it now
                pretty_print << "<" << cur_node->GetName() << ">";
                pretty_print << cur_node->GetNodeContent() ;
                pretty_print << "</" << cur_node->GetName() << ">\n";
            }
            else if (cur_node==doc.GetDocumentNode())
            {
                std::stack<wxXmlNode *> nodes_to_add;
                wxXmlNode *child = cur_node->GetChildren();
                while (child)
                {
                    nodes_to_add.push(child);
                    child = child->GetNext();
                }

                while (!nodes_to_add.empty())
                {
                    nodes_in_progress.push(nodes_to_add.top());
                    nodes_to_add.pop();
                }
            }
            else if (cur_node->GetType()==wxXML_COMMENT_NODE)
            {
                pretty_print << "<!-- " << cur_node->GetContent() << " -->\n";
            }
            //insert checks for other types of nodes with special
            //printing requirements here
            else
            {
                //otherwise, mark the node as visited and then put it back
                visited_nodes.insert(cur_node);
                nodes_in_progress.push(cur_node);

                //If we push the children in order, they'll be popped
                //in reverse order.
                std::stack<wxXmlNode *> nodes_to_add;
                wxXmlNode *child = cur_node->GetChildren();
                while (child)
                {
                    nodes_to_add.push(child);
                    child = child->GetNext();
                }

                while (!nodes_to_add.empty())
                {
                    nodes_in_progress.push(nodes_to_add.top());
                    nodes_to_add.pop();
                }

                pretty_print <<"<" << cur_node->GetName() << ">\n";
            }
        }
    }

    return pretty_print;
}