wxWidgets 中漂亮的打印 XML

Pretty printing XML in wxWidgets

我正在写一个从 wxStyledTextCtrl 派生的 class,我希望它在给定 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

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

有没有简单的解决办法?不,但是如果你想写你自己的漂亮的打印功能,你基本上需要在 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;
}