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;
}
我正在写一个从 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;
}