i am writing a c++ function that will parse .xml file.
i Used system("grep"); type system call to use linux command. now my problem is that i want to select more than one line in given tag. ex.
content of .xml file
====================
<state>
<text> hi this is first li </text>
<sec> dsfn sdlkf sfd </sec>
</state>
===================
i want to print all content between and tag. which and how i can use linux commands.
plz help me....thanks i advance.
Parsing XML using grep is really not a good idea, you should use some c++ xml parsing library like this one:
http://xerces.apache.org/xerces-c/index.html
exec, execve or system calls: demo
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char* args[])
{
exitcode = system("xsltprox textonly.xslt input.xml > output");
// exitcode = exec("xsltproc", "textonly.xslt", "input.xml");
int exitcode;
}
Proceed to fopen output (or std::fstream reader("output") if you fancy). Note that system is quickly a security hole, so you shouldn't use it in critical apps (like daemons).
Using exec you could redirect. So you could perhaps open a pipe() from your program, fork(), in the child assign the stdout filedescriptor to the pipe() (see dup2 call) and exec in the child.
The parent process can then read the output from the pipe without need for a temp file.
All of this should be on a zillion tutorials, which I don't have to the time to google for you right now.
May I suggest using perl or shell script. If you post an actual example I could show you the code in both shell and c/c++
Update here is how to do it with XSLT
textonly.xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//*[text()]">
<xsl:if test="text()">
<xsl:value-of select="text()"/>:
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
output demo:
o399hee#OWW00837 ~/stacko
$ xsltproc.exe textonly.xslt input.xml
:
hi this is first li :
dsfn sdlkf sfd :
Use the C functions popen() and pclose()
Here's an example of how to use them:
#include <string>
#include <cstdio>
#include <errno.h>
#include <fstream>
int execShellCommand( const std::string command,
std::string& commandOutput )
{
FILE *fp;
char charBuf;
std::ostringstream stdoutBuffer;
int status;
std::ostringstream errmsg;
// Execute command and save its output to stdout
fp = popen( command.c_str( ), "r" );
if ( fp == NULL ) {
// error handling
} else {
while ( ( charBuf = fgetc( fp ) ) != EOF ) {
stdoutBuffer << charBuf;
}
}
// Wait for completion of command and return its exit status
status = pclose( fp );
if ( status == -1 ) {
// error handling
} else {
commandOutput = stdoutBuffer.str( );
return WEXITSTATUS( status ); // convert exit status
}
}
int main(){
std::string command = "l | grep lib";
std::string commandOutput;
int exitCode = execShellCommand( command, commandOutput);
}
Related
Previously, I have asked Qt translations in C++ project are rendered as question marks in cmd and powershell question. The point of the question was that the help message of .\app -h, translated to Cyrillic, is rendered as ?????????.
Since then, I discovered that in https://github.com/RSATom/Qt/blob/master/qtbase/src/corelib/tools/qcommandlineparser.cpp, the Qt messages are printed with qInfo("%ls", qUtf16Printable(message)) on Windows.
In cmd.exe or poweshell.exe I get question marks ?????????, when trying to output a Cyrillic message this way.
I tried to change the font of cmd.exe and powershell.exe to Lucida Console and to execute chcp 10000 (as proposed here UTF-16 on cmd.exe), but this does not help.
Here is the minimum reproducible example:
// > cl main.cpp /I C:\Qt\5.12.12\msvc2017_64\include
// > link main.obj /LIBPATH C:\Qt\5.12.12\msvc2017_64\lib\Qt5Core.lib
#include "QtCore/QtGlobal"
#include "QtCore/QString"
int main()
{
qInfo("%ls", qUtf16Printable("Привет"));
return 0;
}
// > main.exe
// ??????
I would really appreciate any help. There are two problems here. The first: how can I use QCommandLineParser under Windows. The second: if QCommandLineParser (using qInfo("%ls", qUtf16Printable(message))) is okay and not a bug, then how can I make cmd show it all right.
I don't pretend on the answer, but on Windows for Unicode console output you should do something similar to:
#include <QDebug>
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
void myMessageOutput( QtMsgType type, const QMessageLogContext & context, const QString & msg )
{
Q_UNUSED( context );
std::wcout << msg.toStdWString() << std::endl;
if( type == QtFatalMsg )
abort();
}
int main()
{
_setmode( _fileno( stdout ), _O_U16TEXT );
qInstallMessageHandler( myMessageOutput );
const std::wstring rs = L"Привет";
const auto s = QString::fromStdWString( rs );
std::wcout << s.toStdWString() << std::endl;
qDebug() << s;
qInfo() << s;
return 0;
}
Accidentally I found the solution. You should create following manifest file for your executable:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>
Let it will be named as app.manifest. In CMake project just add app.manifest into sources of your executable.
In the main() function add two lines of code:
#include <Windows.h>
int main( int argc, char ** argv )
{
SetConsoleCP( GetACP() );
SetConsoleOutputCP( GetACP() );
}
And voila...
Printing should be done using UTF-8, so:
// 1 - works.
QTextStream s( stdout );
s << QString( "Вот оно!!!\n" ) << Qt::flush;
// 2 - works.
fputs( qPrintable( QString( "Опа-на...\n" ) ), stdout );
// 3 - works.
std::cout << u8"std::cout работает!!!\n";
// 4 - DOES NOT work.
std::wcout << L"wcout НЕ работает!!!\n";
I am newbie to xml and xslt area. I have written simple COM utility to transform xsl using xslt. But is failing at transformNodeToObject function call. I am using visual studio 15.
As you can see i am using the msxml6.dll import.
There was another type of call m_hrDOMInitStatus = CoCreateInstance(MSXML2::CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, MSXML2::IID_IXMLDOMDocument3, (void**)&m_pDoc); Not sure whether i need to use this API
#include "stdafx.h"
#include <windows.h>
#include "iostream"
#include <WTypes.h>
#include <comdef.h>
#include <wchar.h>
#include <vector>
#import <msxml6.dll>
using namespace MSXML2;
using namespace std;
int main()
{
HRESULT hResult = S_OK;
hResult = CoInitialize(NULL);
if (FAILED(hResult))
{
cerr << "Failed to initialize COM environment" << endl;
return 0;
}
// MSXML COM smart pointers
// Use the Document2 class to enable schema validation
IXMLDOMDocument2Ptr spDocSource;
IXMLDOMDocument2Ptr spDocResult;
IXMLDOMDocument2Ptr spDocStylesheet;
struct IDispatch * pDispatch;
// Create the COM DOM Document objects
hResult = spDocSource.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Source Document instance" << endl;
return 1;
}
hResult = spDocResult.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Result Document instance" << endl;
return 1;
}
hResult = spDocStylesheet.CreateInstance(__uuidof(DOMDocument60));
if FAILED(hResult)
{
cerr << "Failed to create Stylesheet Document instance" << endl;
return 1;
}
// Load the source document
spDocSource->async = VARIANT_FALSE;
hResult = spDocSource->load("xmlinputfile.xml");
if (hResult != VARIANT_TRUE)
{
cout << "Error parsing xmlinputfile.xml" << endl;
return 1;
}
spDocSource->async = VARIANT_FALSE;
hResult = spDocSource->load("XSLTFile1.xslt");
if (hResult != VARIANT_TRUE)
{
cout << "Error parsing XSLTFile1.xml" << endl;
return 1;
}
spDocResult->QueryInterface(IID_IDispatch, (void **)&pDispatch);
VARIANT vResultDoc;
vResultDoc.vt = VT_DISPATCH;
vResultDoc.pdispVal = pDispatch;
hResult = spDocSource->transformNodeToObject(spDocStylesheet, vResultDoc);
if FAILED(hResult)
{
cout << "Error in performing transformation" << endl;
return 1;
}
return 0;
}
xml input:
_____________
<?xml version="1.0"?>
-<MODEL-LIST ENTERPRISE-XML-VERSION="3">
<MODEL TYPE="Enhanced Macrocell" ID="450 MHz Default"> </MODEL>
</MODEL-LIST>
xslt:
----
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<MODEL-LIST>
<xsl:for-each select="MODEL">
<xsl:element name="MODEL">
<xsl:attribute name="ID">
<xsl:value-of select="#ID"/>
</xsl:attribute>
<xsl:attribute name="TYPE">
<xsl:value-of select="#TYPE"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</MODEL-LIST>
</xsl:template>
</xsl:stylesheet>
The Microsoft online examples on using MSXML with smart pointers, like https://msdn.microsoft.com/en-us/ie/ms766389(v=vs.100), suggest that the call to transformNode would simply work as spDocSource->transformNodeToObject(spDocStylesheet, spDocResult.GetInterfacePtr()).
I think this is due to KB of CVE-2019-1357.
Does the phenomenon not stop when the following KB is uninstalled?
KB4522007: Windows 7 SP1/8.1/ServerR2 SP1/2012(IE10/IE11)/2012 R2/2008 SP2(IE9)
KB4522009: Windows 10(RTM、build10240)
KB4522010: Windows 10 ver1607/Server 2016
KB4522011: Windows 10 ver1703
KB4522012: Windows 10 ver1709
KB4522014: Windows 10 ver1803
KB4522015: Windows 10 ver1809/Server 2019
KB4522016: Windows 10 ver1903
For some reason I can not read data from a xml file properly.
For example instead of "Schrüder" I get something like "Schrüder".
My code:
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("C:\\Users\\Admin\\Desktop\\Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChild()->GetText();
cout << test << endl;
return 0;
}
Part of XML:
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Notice that if I convert it to ANSI and change the encoding type to "ISO-8859-15" it works fine.
I read that something like "LoadFile( filename, TIXML_ENCODING_UTF8 )" should help. However that's not the case (error: Invalid arguments, it just expects a const char). I have the latest version of TinyXML2 (I guess?). I downloaded it just a couple minutes ago from https://github.com/leethomason/tinyxml2.
Any ideas?
Edit: When I write the string to a .xml or .txt file it works fine. There might be some problem with the eclipse ide console. Anyway, when I try to send the string via E-Mail, I also get the same problems. Here's the MailSend script:
bool sendMail(std::string params) {
if( (int) ShellExecute(NULL, "open", "H:\\MailSend\\MailSend_anhang.exe", params.c_str(), NULL, SW_HIDE) <= 32 )
return false;
return true;
}
I call it in the main method like this:
sendMail("-f:d.nitschmann#example.com -t:person2#example.com -s:Subject -b:Body " + test);
I think the problem is with your terminal; can you try run your test code in a different terminal ? one with known good UTF-8 support ?
Output with terminal in UTF-8 mode:
$ ./a.out
Success
Schrüder
Output with terminal in ISO-8859-15 mode:
$ ./a.out
Success
SchrÃŒder
Also - please try and follow http://sscce.org/ - for posterity sake here is your code with everything needed to compile (17676169.cpp):
#include <tinyxml2.h>
#include <string>
#include <iostream>
using namespace std;
using namespace tinyxml2;
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChildElement()->GetText();
cout << test << endl;
return 0;
}
compiled with:
g++ -o 17676169 17676169.cpp -ltinyxml2
and uuencoded Test.xml - to ensure exact same data is used
begin 660 Test.xml
M/#]X;6P#=F5R<VEO;CTB,2XP(B!E;F-O9&EN9STB551&+3#B/SX*/&UY6$U,
M/#H#("`#/&UY.E185%]55$8X5&5S=#Y38VARP[QD97(\+VUY.E185%]55$8X
/5&5S=#X*/"]M>5A-3#X*
`
end
Edit 1:
If you want to confirm this theory - run this in eclipse:
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream ifs("Test.xml");
std::string xml_data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
std::cout << xml_data;
}
Output with terminal in UTF-8 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Output with terminal in ISO-8859-15 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>SchrÃŒder</my:TXT_UTF8Test>
</myXML>
I`m try to realize how to use TinyXML library.
I have to parse this conf file:
<?xml version="1.0" encoding="UTF-8"?>
<Client>
<port num = "20035">
<server_addr ip="127.0.0.1">
<AV_list>
<AV>
<AVNAME>BitDefender</AVNAME>>
<AVPATH> C:\Program Files\Common Files\BitDefender\BitDefender Threat Scanner\av64bit_26308\bdc.exe </AVPATH>
<AVMASK>0x80000000</AVMASK>
<AVCOMMANDLINE> %avpath% \log=%avlog% %scanpath% </AVCOMMANDLINE>
<AVREGEX>(%scanpath%.*?)+(([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4})+(.+[a-zA-Z_])</AVREGEX>
<AVLOG>C:\log\bd_log.txt</AVLOG>
</AV>
</AV_list>
</Client>
And c++ code
#include "stdafx.h"
#include "iostream"
#include "tinyxml.h"
int main(int argc, char* argv[])
{
TiXmlDocument doc( "D:\\client_conf.xml" );
bool loadOkay = doc.LoadFile();
if ( loadOkay )
printf("Yes \n");
else
printf("No \n");
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlText* pText;
TiXmlHandle hRoot(0);
pElem = hDoc.FirstChildElement().Element();
if (!pElem)
printf("error element");
hRoot = TiXmlHandle(pElem);
pElem = hRoot.FirstChild("server_addr").Element();
const char* info = pElem->Attribute("ip");
printf( "%s \n", info);
pElem = hRoot.FirstChild("port").Element();
info = pElem->Attribute("num");
printf( "%s \n", info);
system("pause");
return 0;
}
Now I can get first two param, but dont figure out how to reach "AV_list" block. Any help will be appreciated. (:
Have a look at the TinyXml Documentation. Your friend is the TiXmlNode Class Reference. You may use most of the Node functions also on TiXmlElements.
You already use the FirstChild() function to get the first child of an element; use the NextSibling() function to iterate over all elements. You can also use the NextSiblingElement() function to get the element directly.
Antother more sophisticated solution would be to use XPath to retrieve elements from the xml file. There is TinyXPath that builds on top of TinyXML. It needs some knowledge of XPath but it might be worth it. (XPath standard)
I'm having a heck of a time figuring out how to use the sax parser for libxml2. Can someone post an example that parses this XML ( yes, without the <xml...> header and footer tags, if that can be parsed by the libxml2 sax parser):
<hello foo="bar">world</hello>
The parser should print out the data enclosed in element hello and also grab the value of attribute foo.
I'm working on this example, but hoping that someone else beats me to the punch since I'm not making much progress. The Google hasn't yielded any complete, working examples for libxml2 sax parser.
Adapted from http://julp.developpez.com/c/libxml2/?page=sax
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
void start_element_callback(void *user_data, const xmlChar *name, const xmlChar **attrs) {
printf("Beginning of element : %s \n", name);
while (NULL != attrs && NULL != attrs[0]) {
printf("attribute: %s=%s\n",attrs[0],attrs[1]);
attrs = &attrs[2];
}
}
int main() {
const char* xml_path = "hello_world.xml";
FILE *xml_fh = fopen(xml_path,"w+");
fputs("<hello foo=\"bar\" baz=\"baa\">world</hello>",xml_fh);
fclose(xml_fh);
// Initialize all fields to zero
xmlSAXHandler sh = { 0 };
// register callback
sh.startElement = start_element_callback;
xmlParserCtxtPtr ctxt;
// create the context
if ((ctxt = xmlCreateFileParserCtxt(xml_path)) == NULL) {
fprintf(stderr, "Erreur lors de la création du contexte\n");
return EXIT_FAILURE;
}
// register sax handler with the context
ctxt->sax = &sh;
// parse the doc
xmlParseDocument(ctxt);
// well-formed document?
if (ctxt->wellFormed) {
printf("XML Document is well formed\n");
} else {
fprintf(stderr, "XML Document isn't well formed\n");
//xmlFreeParserCtxt(ctxt);
return EXIT_FAILURE;
}
// free the memory
// xmlFreeParserCtxt(ctxt);
return EXIT_SUCCESS;
}
This produces output:
Beginning of element : hello
attribute: foo=bar
attribute: baz=baa
XML Document is well formed
Compiled with the following command on Ubuntu 10.04.1:
g++ -I/usr/include/libxml2 libxml2_hello_world.cpp /usr/lib/libxml2.a -lz\
-o libxml2_hello_world
Can I suggest rapidxml?