Use TinyXML to write XML files

This commit is contained in:
PKEuS 2013-08-07 16:30:55 +02:00
parent a9a5dc0354
commit 758d68519d
4 changed files with 69 additions and 88 deletions

View File

@ -1729,11 +1729,11 @@ void XMLDocument::PrintError() const
}
XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_elementJustOpened( false ),
_firstElement( true ),
_fp( file ),
_depth( 0 ),
_depth( depth ),
_textDepth( -1 ),
_processEntities( true ),
_compactMode( compact )
@ -1840,7 +1840,7 @@ void XMLPrinter::PrintString( const char* p, bool restricted )
void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
{
if ( writeBOM ) {
static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Print( "%s", bom );
}
if ( writeDec ) {
@ -1858,6 +1858,8 @@ void XMLPrinter::OpenElement( const char* name )
if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Print( "\n" );
}
if ( !_compactMode ) {
PrintSpace( _depth );
}

View File

@ -14,6 +14,7 @@ not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
@ -125,11 +126,9 @@ class XMLDocument;
class XMLElement;
class XMLAttribute;
class XMLComment;
class XMLNode;
class XMLText;
class XMLDeclaration;
class XMLUnknown;
class XMLPrinter;
/*
@ -144,14 +143,14 @@ public:
enum {
NEEDS_ENTITY_PROCESSING = 0x01,
NEEDS_NEWLINE_NORMALIZATION = 0x02,
COLLAPSE_WHITESPACE = 0x04,
COLLAPSE_WHITESPACE = 0x04,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_NAME = 0,
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
COMMENT = NEEDS_NEWLINE_NORMALIZATION
ATTRIBUTE_NAME = 0,
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
COMMENT = NEEDS_NEWLINE_NORMALIZATION
};
StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
@ -1884,7 +1883,7 @@ public:
If 'compact' is set to true, then output is created
with only required whitespace and newlines.
*/
XMLPrinter( FILE* file=0, bool compact = false );
XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
~XMLPrinter() {}
/** If streaming, write the BOM and declaration. */

View File

@ -22,6 +22,8 @@
#include "tokenlist.h"
#include "token.h"
#include <tinyxml2.h>
#include <cassert>
#include <sstream>
#include <vector>
@ -177,95 +179,73 @@ std::string ErrorLogger::ErrorMessage::getXMLHeader(int xml_version)
{
// xml_version 1 is the default xml format
tinyxml2::XMLPrinter printer;
// standard xml header
std::ostringstream ostr;
ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
// version 1 header
if (xml_version <= 1) {
ostr << "<results>";
}
printer.PushDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");
// header
printer.OpenElement("results");
// version 2 header
else {
ostr << "<results version=\"" << xml_version << "\">\n";
ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>\n";
ostr << " <errors>";
if (xml_version == 2) {
printer.PushAttribute("version", xml_version);
printer.OpenElement("cppcheck");
printer.PushAttribute("version", CppCheck::version());
printer.CloseElement();
printer.OpenElement("errors");
}
return ostr.str();
return std::string(printer.CStr()) + '>';
}
std::string ErrorLogger::ErrorMessage::getXMLFooter(int xml_version)
{
return (xml_version<=1) ? "</results>" : " </errors>\n</results>";
}
static std::string stringToXml(std::string s)
{
// convert a string so it can be save as xml attribute data
std::string::size_type pos = 0;
while ((pos = s.find_first_of("<>&\"\n", pos)) != std::string::npos) {
if (s[pos] == '<')
s.insert(pos + 1, "&lt;");
else if (s[pos] == '>')
s.insert(pos + 1, "&gt;");
else if (s[pos] == '&')
s.insert(pos + 1, "&amp;");
else if (s[pos] == '"')
s.insert(pos + 1, "&quot;");
else if (s[pos] == '\n')
s.insert(pos + 1, "&#xa;");
s.erase(pos, 1);
++pos;
}
return s;
return (xml_version<=1) ? "</results>" : " </errors>\n</results>";
}
std::string ErrorLogger::ErrorMessage::toXML(bool verbose, int version) const
{
// Save this ErrorMessage as an XML element
std::ostringstream xml;
// The default xml format
if (version == 1) {
// No inconclusive messages in the xml version 1
if (_inconclusive)
return "";
xml << "<error";
tinyxml2::XMLPrinter printer(0, false, 1);
printer.OpenElement("error");
if (!_callStack.empty()) {
xml << " file=\"" << stringToXml(_callStack.back().getfile()) << "\"";
xml << " line=\"" << _callStack.back().line << "\"";
printer.PushAttribute("file", _callStack.back().getfile().c_str());
printer.PushAttribute("line", _callStack.back().line);
}
xml << " id=\"" << _id << "\"";
xml << " severity=\"" << (_severity == Severity::error ? "error" : "style") << "\"";
xml << " msg=\"" << stringToXml(verbose ? _verboseMessage : _shortMessage) << "\"";
xml << "/>";
printer.PushAttribute("id", _id.c_str());
printer.PushAttribute("severity", (_severity == Severity::error ? "error" : "style"));
printer.PushAttribute("msg", (verbose ? _verboseMessage : _shortMessage).c_str());
printer.CloseElement();
return printer.CStr();
}
// The xml format you get when you use --xml-version=2
else if (version == 2) {
xml << " <error";
xml << " id=\"" << _id << "\"";
xml << " severity=\"" << Severity::toString(_severity) << "\"";
xml << " msg=\"" << stringToXml(_shortMessage) << "\"";
xml << " verbose=\"" << stringToXml(_verboseMessage) << "\"";
tinyxml2::XMLPrinter printer(0, false, 2);
printer.OpenElement("error");
printer.PushAttribute("id", _id.c_str());
printer.PushAttribute("severity", Severity::toString(_severity).c_str());
printer.PushAttribute("msg", _shortMessage.c_str());
printer.PushAttribute("verbose", _verboseMessage.c_str());
if (_inconclusive)
xml << " inconclusive=\"true\"";
xml << ">" << std::endl;
printer.PushAttribute("inconclusive", "true");
for (std::list<FileLocation>::const_reverse_iterator it = _callStack.rbegin(); it != _callStack.rend(); ++it) {
xml << " <location";
xml << " file=\"" << stringToXml((*it).getfile()) << "\"";
xml << " line=\"" << (*it).line << "\"";
xml << "/>" << std::endl;
printer.OpenElement("location");
printer.PushAttribute("file", (*it).getfile().c_str());
printer.PushAttribute("line", (*it).line);
printer.CloseElement();
}
xml << " </error>";
printer.CloseElement();
return printer.CStr();
}
return xml.str();
return "";
}
void ErrorLogger::ErrorMessage::findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith)

View File

@ -187,7 +187,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
ASSERT_EQUALS(" <error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
}
void ToXmlLocations() const {
@ -203,7 +203,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
ASSERT_EQUALS(" <error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
}
void ToVerboseXml() const {
@ -215,7 +215,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
ASSERT_EQUALS(" <error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
}
void ToVerboseXmlLocations() const {
@ -231,7 +231,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
ASSERT_EQUALS(" <error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
}
void ToXmlV2() const {
@ -242,14 +242,14 @@ private:
locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n");
header += " <cppcheck version=\"";
header += " <cppcheck version=\"";
header += CppCheck::version();
header += "\"/>\n <errors>";
header += "\"/>\n <errors>";
ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2));
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\"");
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\"");
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
ASSERT_EQUALS(message, msg.toXML(false, 2));
}
@ -265,15 +265,15 @@ private:
locs.push_back(loc2);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n");
header += " <cppcheck version=\"";
header += " <cppcheck version=\"";
header += CppCheck::version();
header += "\"/>\n <errors>";
header += "\"/>\n <errors>";
ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2));
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\"");
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\"");
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
message += " <location file=\"bar.cpp\" line=\"8\"/>\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
message += " <location file=\"bar.cpp\" line=\"8\"/>\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
ASSERT_EQUALS(message, msg.toXML(false, 2));
}
@ -292,9 +292,9 @@ private:
ASSERT_EQUALS("", msg.toXML(false, 1));
// xml version 2 error message
ASSERT_EQUALS(" <error id=\"errorId\" severity=\"error\" msg=\"Programming error\" verbose=\"Programming error\" inconclusive=\"true\">\n"
" <location file=\"foo.cpp\" line=\"5\"/>\n"
" </error>",
ASSERT_EQUALS(" <error id=\"errorId\" severity=\"error\" msg=\"Programming error\" verbose=\"Programming error\" inconclusive=\"true\">\n"
" <location file=\"foo.cpp\" line=\"5\"/>\n"
" </error>",
msg.toXML(false, 2));
}