acceleration of function prettyprint

This commit is contained in:
Svetlana Kulikova
2020-07-27 18:03:15 +03:00
parent d309db527f
commit 98f26e034b
4 changed files with 26329 additions and 26379 deletions

View File

@ -3,9 +3,8 @@
#include <string>
#include "gumbo-parser/src/gumbo.h"
#include "../../../DesktopEditor/xml/include/xmlutils.h"
#include "../../../DesktopEditor/xml/include/xmlencoding.h"
#include "../../../DesktopEditor/common/File.h"
#include "../../../DesktopEditor/common/StringBuilder.h"
#include "../../../UnicodeConverter/UnicodeConverter.h"
#ifndef HTMLTOXHTML_USE_DYNAMIC_LIBRARY
@ -22,7 +21,7 @@ static std::string special_handling = "|html|body|";
static std::string no_entity_sub = "|script|style|";
static std::string treat_like_inline = "|p|";
static std::string prettyprint(GumboNode*, int lvl, const std::string indent_chars);
static std::string prettyprint(GumboNode*);
static std::wstring htmlToXhtml(const std::wstring& sFile)
{
@ -46,6 +45,7 @@ static std::wstring htmlToXhtml(const std::wstring& sFile)
std::string sEncoding = sFileContent.substr(posEncoding, posEnd - posEncoding);
if (sEncoding != "utf-8" && sEncoding != "UTF-8")
{
sFileContent.replace(posEncoding, posEnd - posEncoding, "UTF-8");
NSUnicodeConverter::CUnicodeConverter oConverter;
sRes = oConverter.toUnicode(sFileContent, sEncoding.c_str());
sFileContent = U_TO_UTF8(sRes);
@ -56,83 +56,64 @@ static std::wstring htmlToXhtml(const std::wstring& sFile)
GumboOutput* output = gumbo_parse_with_options(&options, sFileContent.data(), sFileContent.length());
// prettyprint
std::string indent_chars = " ";
std::string sR = prettyprint(output->document, 0, indent_chars);
std::string sR = prettyprint(output->document);
// Вставка кодировки в файл
if(sR.length() > 5)
{
std::string sSub = sR.substr(0, 5);
if(sSub != "<?xml")
sR = "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" + sR;
sR = "<?xml version=\'1.0\' encoding=\'UTF-8\'?>" + sR;
}
// Конвертирование из string utf8 в wstring
return UTF8_TO_U(sR);
}
// Убирает в конце бесполезные символы
static inline void rtrim(std::string& s)
{
s.erase(s.find_last_not_of(" \n\r\t") + 1);
}
// Убирает в начале бесполезные символы
static inline void ltrim(std::string& s)
{
s.erase(0,s.find_first_not_of(" \n\r\t"));
}
// Заменяет в строке s все символы s1 на s2
static void replace_all(std::string& s, const char* s1, const char* s2)
static void replace_all(std::string& s, std::string s1, std::string s2)
{
std::string t1(s1);
size_t len = t1.length();
size_t pos = s.find(t1);
size_t len = s1.length();
size_t pos = s.find(s1);
while (pos != std::string::npos)
{
s.replace(pos, len, s2);
pos = s.find(t1, pos + len);
pos = s.find(s1, pos + len);
}
}
// Заменяет сущности &,<,> в text
static std::string substitute_xml_entities_into_text(const std::string &text)
static void substitute_xml_entities_into_text(std::string &text)
{
std::string result = text;
// replacing & must come first
replace_all(result, "&", "&amp;");
replace_all(result, "<", "&lt;");
replace_all(result, ">", "&gt;");
return result;
replace_all(text, "&", "&amp;");
replace_all(text, "<", "&lt;");
replace_all(text, ">", "&gt;");
}
// Заменяет сущности ",' в text
static std::string substitute_xml_entities_into_attributes(char quote, const std::string &text)
static void substitute_xml_entities_into_attributes(char quote, std::string &text)
{
std::string result = substitute_xml_entities_into_text(text);
substitute_xml_entities_into_text(text);
if (quote == '"')
replace_all(result,"\"","&quot;");
replace_all(text, "\"", "&quot;");
else if (quote == '\'')
replace_all(result,"'","&apos;");
return result;
replace_all(text, "'", "&apos;");
}
static std::string handle_unknown_tag(GumboStringPiece *text)
static std::string handle_unknown_tag(GumboStringPiece* text)
{
std::string tagname = "";
if (text->data == NULL) {
return tagname;
return "";
}
GumboStringPiece gsp = *text;
gumbo_tag_from_original_text(&gsp);
tagname = std::string(gsp.data, gsp.length);
return tagname;
return std::string(gsp.data, gsp.length);
}
static std::string get_tag_name(GumboNode *node)
static std::string get_tag_name(GumboNode* node)
{
std::string tagname = (node->type == GUMBO_NODE_DOCUMENT ? "document" : gumbo_normalized_tagname(node->v.element.tag));
if (tagname.empty())
@ -141,65 +122,59 @@ static std::string get_tag_name(GumboNode *node)
}
static std::string build_doctype(GumboNode *node)
static void build_doctype(GumboNode* node, NSStringUtils::CStringBuilderA& oBuilder)
{
std::string results = "";
if (node->v.document.has_doctype)
{
results.append("<!DOCTYPE ");
results.append(node->v.document.name);
oBuilder.WriteString("<!DOCTYPE ");
oBuilder.WriteString(node->v.document.name);
std::string pi(node->v.document.public_identifier);
if ((node->v.document.public_identifier != NULL) && !pi.empty())
{
results.append(" PUBLIC \"");
results.append(node->v.document.public_identifier);
results.append("\" \"");
results.append(node->v.document.system_identifier);
results.append("\"");
oBuilder.WriteString(" PUBLIC \"");
oBuilder.WriteString(pi);
oBuilder.WriteString("\" \"");
oBuilder.WriteString(node->v.document.system_identifier);
oBuilder.WriteString("\"");
}
results.append(">\n");
oBuilder.WriteString(">");
}
return results;
}
static std::string build_attributes(GumboAttribute * at, bool no_entities)
static void build_attributes(GumboAttribute* at, bool no_entities, NSStringUtils::CStringBuilderA& atts)
{
std::string atts = "";
atts.append(" ");
atts.append(at->name);
// how do we want to handle attributes with empty values
// <input type="checkbox" checked /> or <input type="checkbox" checked="" />
if ((!std::string(at->value).empty()) ||
(at->original_value.data[0] == '"') ||
(at->original_value.data[0] == '\''))
std::string sVal(at->value);
char quote = at->original_value.data[0];
if ((!sVal.empty()) || (quote == '"') || (quote == '\''))
{
// determine original quote character used if it exists
char quote = at->original_value.data[0];
std::string qs = "";
if (quote == '\'') qs = std::string("'");
if (quote == '"') qs = std::string("\"");
atts.WriteString(" ");
atts.WriteString(at->name);
atts.append("=");
atts.append(qs);
atts.append(no_entities ? at->value : substitute_xml_entities_into_attributes(quote, std::string(at->value)));
atts.append(qs);
// determine original quote character used if it exists
std::string qs = "";
if (quote == '\'')
qs = "'";
else if (quote == '"')
qs = "\"";
atts.WriteString("=");
atts.WriteString(qs);
if(!no_entities)
substitute_xml_entities_into_attributes(quote, sVal);
atts.WriteString(sVal);
atts.WriteString(qs);
}
return atts;
}
static std::string prettyprint_contents(GumboNode* node, int lvl, const std::string indent_chars)
static std::string prettyprint_contents(GumboNode* node)
{
std::string contents = "";
std::string tagname = get_tag_name(node);
std::string key = "|" + tagname + "|";
NSStringUtils::CStringBuilderA contents;
std::string key = "|" + get_tag_name(node) + "|";
bool no_entity_substitution = no_entity_sub.find(key) != std::string::npos;
bool keep_whitespace = preserve_whitespace.find(key) != std::string::npos;
bool is_inline = nonbreaking_inline.find(key) != std::string::npos;
bool pp_okay = !is_inline && !keep_whitespace;
GumboVector* children = &node->v.element.children;
@ -209,79 +184,58 @@ static std::string prettyprint_contents(GumboNode* node, int lvl, const std::str
if (child->type == GUMBO_NODE_TEXT)
{
std::string val = (no_entity_substitution ? std::string(child->v.text.text) : substitute_xml_entities_into_text(std::string(child->v.text.text)));
if (pp_okay)
rtrim(val);
if (pp_okay && (contents.length() == 0))
{
// add required indentation
char c = indent_chars.at(0);
int n = indent_chars.length();
contents.append(std::string((lvl - 1) * n, c));
}
contents.append(val);
std::string val(child->v.text.text);
if(!no_entity_substitution)
substitute_xml_entities_into_text(val);
contents.WriteString(val);
}
else if ((child->type == GUMBO_NODE_ELEMENT) || (child->type == GUMBO_NODE_TEMPLATE))
{
std::string val = prettyprint(child, lvl, indent_chars);
// remove any indentation if this child is inline and not first child
std::string childname = get_tag_name(child);
std::string childkey = "|" + childname + "|";
if ((nonbreaking_inline.find(childkey) != std::string::npos) && (contents.length() > 0))
ltrim(val);
contents.append(val);
std::string val = prettyprint(child);
contents.WriteString(val);
}
else if (child->type == GUMBO_NODE_WHITESPACE)
{
if (keep_whitespace || is_inline)
contents.append(std::string(child->v.text.text));
contents.WriteString(child->v.text.text);
}
else if (child->type != GUMBO_NODE_COMMENT)
{
// Сообщение об ошибке
// Does this actually exist: (child->type == GUMBO_NODE_CDATA)
fprintf(stderr, "unknown element of type: %d\n", child->type);
// fprintf(stderr, "unknown element of type: %d\n", child->type);
}
}
return contents;
return contents.GetData();
}
static std::string prettyprint(GumboNode* node, int lvl, const std::string indent_chars)
static std::string prettyprint(GumboNode* node)
{
NSStringUtils::CStringBuilderA oBuilder;
// special case the document node
if (node->type == GUMBO_NODE_DOCUMENT)
{
std::string results = build_doctype(node);
results.append(prettyprint_contents(node,lvl+1,indent_chars));
return results;
build_doctype(node, oBuilder);
oBuilder.WriteString(prettyprint_contents(node));
return oBuilder.GetData();
}
std::string close = "";
std::string closeTag = "";
std::string atts = "";
NSStringUtils::CStringBuilderA atts;
std::string tagname = get_tag_name(node);
std::string key = "|" + tagname + "|";
bool need_special_handling = special_handling.find(key) != std::string::npos;
bool is_empty_tag = empty_tags.find(key) != std::string::npos;
bool no_entity_substitution = no_entity_sub.find(key) != std::string::npos;
bool keep_whitespace = preserve_whitespace.find(key) != std::string::npos;
bool is_inline = nonbreaking_inline.find(key) != std::string::npos;
bool inline_like = treat_like_inline.find(key) != std::string::npos;
bool pp_okay = !is_inline && !keep_whitespace;
char c = indent_chars.at(0);
int n = indent_chars.length();
// build attr string
const GumboVector * attribs = &node->v.element.attributes;
for (int i = 0; i < attribs->length; ++i)
{
GumboAttribute* at = static_cast<GumboAttribute*>(attribs->data[i]);
atts.append(build_attributes(at, no_entity_substitution));
build_attributes(at, no_entity_substitution, atts);
}
// determine closing tag type
@ -290,40 +244,20 @@ static std::string prettyprint(GumboNode* node, int lvl, const std::string inden
else
closeTag = "</" + tagname + ">";
std::string indent_space = std::string((lvl - 1) * n, c);
// prettyprint your contents
std::string contents = prettyprint_contents(node, lvl + 1, indent_chars);
if (need_special_handling)
{
rtrim(contents);
contents.append("\n");
}
std::string contents = prettyprint_contents(node);
char last_char = ' ';
if (!contents.empty())
last_char = contents.at(contents.length() - 1);
// build results
std::string results;
if (pp_okay)
results.append(indent_space);
results.append("<" + tagname + atts + close + ">");
if (pp_okay && !inline_like)
results.append("\n");
if (inline_like)
ltrim(contents);
results.append(contents);
if (pp_okay && !contents.empty() && (last_char != '\n') && (!inline_like))
results.append("\n");
if (pp_okay && !inline_like && !closeTag.empty())
results.append(indent_space);
results.append(closeTag);
if (pp_okay && !closeTag.empty())
results.append("\n");
NSStringUtils::CStringBuilderA results;
results.WriteString("<" + tagname + atts.GetData() + close + ">");
results.WriteString(contents);
results.WriteString(closeTag);
return results;
return results.GetData();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<?xml version='1.0' encoding='utf-8'?>
<html xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fb="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Последнее желание</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
<link href="page_styles.css" rel="stylesheet" type="text/css"/>
</head>
<body class="calibre">
<h1 id="calibre_toc_2" class="calibre7"><a id="TOC_idm140435370588032" class="calibre9"></a><a class="calibre9" id="TOC_idm140435370587904"></a>ГЛАС РАССУДКА I <br class="calibre8"/>
</h1><div class="paragraph">Она пришла под утро.</div>
<div class="paragraph">Вошла осторожно, тихо, бесшумно ступая, плывя по комнате, словно призрак, привидение, а единственным звуком, выдававшим ее движение, был шорох накидки, прикасавшейся к голому телу. Однако именно этот исчезающе тихий, едва уловимый шелест разбудил ведьмака, а может, только вырвал из полусна, в котором он мерно колыхался, словно погруженный в бездонную топь, висящий между дном и поверхностью спокойного моря, среди легонько извивающихся нитей водорослей.</div>
<div class="paragraph">Он не пошевелился, даже не дрогнул. Девушка подпорхнула ближе, сбросила накидку, медленно, нерешительно оперлась коленом о край ложа. Он наблюдал за ней из-под опущенных ресниц, не выдавая себя. Девушка осторожно поднялась на постель, легла на него, обхватила бедрами. Опираясь на напряженные руки, скользнула по его лицу волосами. Волосы пахли ромашкой. Решительно и как бы нетерпеливо наклонилась, коснулась сосочком его века, щеки, губ. Он улыбнулся, медленно, осторожно, нежно взял ее руки в свои. Она выпрямилась, ускользая от его пальцев, лучистая, подсвеченная и от этого света нечеткая в туманном отблеске зари. Он пошевелился, но она решительным нажимом обеих рук остановила его и легкими, но настойчивыми движениями бедер добилась ответа.</div>
<div class="paragraph">Он ответил. Она уже не избегала его рук, откинула голову, встряхнула волосами. Ее кожа была холодной и поразительно гладкой. Глаза, которые он увидел, когда она приблизила свое лицо к его лицу, были огромными и темными, как глаза русалки.</div>
<div class="paragraph">Покачиваясь, он утонул в ромашковом море, а оно взбурлило и зашумело, потеряв покой.</div>
</body></html>

View File

@ -3,6 +3,7 @@
#include "../../Common/3dParty/html/htmltoxhtml.h"
#include "../../DesktopEditor/common/File.h"
#include "../../DesktopEditor/common/Directory.h"
#include "../../DesktopEditor/xml/include/xmlutils.h"
void readFile( XmlUtils::CXmlLiteReader& oLightReader)
{
@ -14,7 +15,7 @@ void readFile( XmlUtils::CXmlLiteReader& oLightReader)
int main()
{
// Файл, который открываем
std::wstring sFile = NSFile::GetProcessDirectory() + L"/../../../examples/test2.html";
std::wstring sFile = NSFile::GetProcessDirectory() + L"/../../../examples/test3.html";
// Директория, где будем создавать xhtml
std::wstring sOutputDirectory = NSFile::GetProcessDirectory() + L"/res";
@ -34,8 +35,8 @@ int main()
bool bRes = oLightReader.FromFile(sOutputDirectory + L"/res.xhtml");
if(bRes)
{
// readFile(oLightReader);
std::cout << (oLightReader.ReadTillEnd() ? "Success" : "Failure") << std::endl;
readFile(oLightReader);
std::cout << "Success" << std::endl;
}
else
std::cout << "Failure" << std::endl;