PDA

View Full Version : Remove element of xml



VitaliBR
3rd February 2011, 23:29
<lista>
<client>
<dns>google.com.br</dns>
<phone>(19)3632-9244</phone>
<name>Google</name>
</client>
<client>
<dns>uol.com.br</dns>
<phone>(16)3307-5496</phone>
<name>Uol</name>
</client>
<client>
<dns>terra.com.br</dns>
<phone>(21)3368-0422</phone>
<name>Terra</name>
</client>
</list>


I wonder how I can delete everything between the tag <client> </client> choosing the name,
eg:
I would like to delete the customer information Google:
<client>
<dns>google.com.br</dns>
<phone>(19)3632-9244</phone>
<name>Google</name>
</client>


Thanks

stampede
4th February 2011, 05:43
Quick and dirty solution could be to use regular expressions (http://doc.qt.nokia.com/latest/qregexp.html).
Yours could look like this (pseudocode):

<client>/*whatever*/<name>/*maybe whitespaces*/ClientToDelete/*maybe whitespaces*/</name>/*whatever*/</client>
Don't forget to set it for minimal match (http://doc.qt.nokia.com/latest/qregexp.html#setMinimal), it'll eat up all your xml otherwise (if it founds ClientToDelete).

helloworld
4th February 2011, 05:48
It would help if you explained a bit how you are parsing the document; i.e., if you are using SAX, DOM, or some other parser.

VitaliBR
4th February 2011, 10:56
It would help if you explained a bit how you are parsing the document; i.e., if you are using SAX, DOM, or some other parser.

lol Sorry guy :)

I'm using the DOM, see:


QString arquivo = "List.xml";

QFile file(arquivo);
QDomDocument doc( "List" );

//Checking if file exists
if(!file.exists())
{
QMessageBox::information(0,tr("Critical Error"),tr("The file %1 does not exist! \ nPlease try to register an account!!").arg(arquivo));
this->close();
}

//Checking if the file can be read and written
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(0,tr("Critical Error"),tr("Failed to open file %1!").arg(arquivo));
file.close();
this->close();
}

//Getting the contents of the old xml
doc.setContent(&file);
file.close();

Thanks

Added after 36 minutes:

I changed the structure of my XML:


<list>
<client name="Google">
<dns>google.com.br</dns>
<phone>+5521XXXXXXXX</phone>
</client>
<client name="Hotmail">
<dns>hotmail.com</dns>
<phone>+5535XXXXXXXX</phone>
</client>
</list>

I created a method to delete, but is not working:


void Remove::RemoveGroup(QDomDocument *twmDomDocument, QString theGroupName )
{
QDomNodeList domTwm = twmDomDocument->elementsByTagName( "client" );

if ( !domTwm.isEmpty() )
{
for ( uint i = 0; i < domTwm.length(); i++ )
{
if ( domTwm.at(i).toElement().attribute( "name" ) == theGroupName )
{
twmDomDocument->removeChild( domTwm.at(i) );
}
}
}
}


void Remove::Remover()
{
RemoveGroup(&leXml(),"Google");
}

QDomDocument Remove::leXml()
{
QString arquivo = "List.xml";

QFile file(arquivo);
QDomDocument doc( "List" );

//Checking if file exists
if(!file.exists())
{
QMessageBox::information(0,tr("Critical Error"),tr("The file %1 does not exist! \ nPlease try to register an account!!").arg(arquivo));
this->close();
}

//Checking if the file can be read and written
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(0,tr("Critical Error"),tr("Failed to open file %1!").arg(arquivo));
file.close();
this->close();
}

//Getting the contents of the old xml
doc.setContent(&file);
file.close();
return doc;
}

Why? :(

VitaliBR
4th February 2011, 19:14
anyone? :(

stampede
4th February 2011, 19:22
A little suggestion:

void Remove::RemoveGroup(QDomDocument *twmDomDocument, QString theGroupName )
{
QDomNodeList domTwm = twmDomDocument->elementsByTagName( "client" );
qDebug() << "start remove: " << theGroupName;
if ( !domTwm.isEmpty() )
{
qDebug() << "not empty... length: " << domTwm.length();
for ( uint i = 0; i < domTwm.length(); i++ )
{
qDebug() << "processing " << i << " -> " << domTwm.at(i).toElement().attribute( "name" );
if ( domTwm.at(i).toElement().attribute( "name" ) == theGroupName )
{
qDebug() << "removing";
twmDomDocument->removeChild( domTwm.at(i) );
}
}
}
}
Whats the output ?

------------------------------
Wait a minute, now I've looked how you are calling your methods. This is not good:

RemoveGroup(&leXml(),"Google");
Dont pass temporary values by pointer or reference, whats the point - leXml() returns a QDomDocument which may be modified by RemoveGroup(), but you cant access it anymore. This is a mess. Try this:

QDomDocument doc = leXml();
RemoveGroup(&doc,"Google");
qDebug() << doc.toString();

VitaliBR
8th February 2011, 09:51
It appeared in the Debug


start remove: "Google"
not empty... length: 1
processing 0 -> "Google"
removing
"<!DOCTYPE List>
<list>
<client>
<dns>google.com.br</dns>
<phone>+55162223232</phone>
<name>Google</name>
</client>
</list>"

stampede
8th February 2011, 10:38
Ok, now I see what's the problem here.
In order to remove child element 'el' with "doc->removeChild( el )", 'el' should be direct child of the "doc" node. <client> is not direct child of your document, its a child of root element of your document, so this will work:

twmDomDocument->documentElement().removeChild( domTwm.at(i) );

---
I have tested it on this document:

<list>
<client name="Google">
<dns>google.com.br</dns>
<phone>+5521XXXXXXXX</phone>
</client>
<client name="Hotmail">
<dns>hotmail.com</dns>
<phone>+5535XXXXXXXX</phone>
</client>
</list>

code:

QFile f("test.xml");
f.open( QIODevice::ReadOnly | QIODevice::Text );
QDomDocument doc;
doc.setContent( &f );
RemoveGroup(&doc,"Google");
qDebug() << doc.toString();

output:

<list>
<client name="Hotmail" >
<dns>hotmail.com</dns>
<phone>+5535XXXXXXXX</phone>
</client>
</list>

VitaliBR
10th February 2011, 10:57
Ok :)

Thanks for your help
I need to save this change in the XML? If yes, how I do it?

stampede
10th February 2011, 19:22
I need to save this change in the XML? If yes, how I do it?
The method you have changes QDomDocument object, which not implies change in file from which you get xml string. To save changes, simply overwrite previous content of the xml file using the updated QDomDocument object.

VitaliBR
11th February 2011, 01:17
But why is not Google removing my XML? :(

the button (action) remover

void Remove::Remover()
{
QFile f("List.xml");
f.open( QIODevice::ReadOnly | QIODevice::Text );
QDomDocument doc;
doc.setContent( &f );
RemoveGroup(&doc,"Google");

QTextStream out(&f);
out << doc.toString();

f.close();

QMessageBox::information(0,tr("Warning!"),tr("The Client %1 has been removed!").arg("Google"));

}

stampede
11th February 2011, 16:25
But why is not Google removing my XML?
What do you mean ? Remove method is not working ? Have you updated it with my previous suggestion ?
Or do you mean that content of file is not updated ? If yes, then well...

f.open( QIODevice::ReadOnly | QIODevice::Text );
//...
QTextStream out(&f);
out << doc.toString();

'f' is still opened in ReadOnly mode when you try to write to it.

VitaliBR
15th February 2011, 11:04
I did so:

void Remove::Remover()
{
QFile f("List.xml");
f.open(QIODevice::WriteOnly);
QDomDocument doc;
doc.setContent( &f );
RemoveGroup(&doc,"Google");

QTextStream out(&f);
out << doc.toString();

f.close();

QMessageBox::information(0,tr("Warning!"),tr("The Client %1 has been removed!").arg("Google"));
}


void Remove::RemoveGroup(QDomDocument *twmDomDocument, QString theGroupName )
{
QDomNodeList domTwm = twmDomDocument->elementsByTagName( "client" );

if ( !domTwm.isEmpty() )
{
for ( uint i = 0; i < domTwm.length(); i++ )
{
if ( domTwm.at(i).toElement().attribute( "name" ) == theGroupName )
{
twmDomDocument->documentElement().removeChild( domTwm.at(i) );
}
}
}
}



But instead of it just delete the Google of the XML, it leaves blank XML file (delete everything) :(

stampede
15th February 2011, 11:50
f.open(QIODevice::WriteOnly);
QDomDocument doc;
doc.setContent( &f );

Now you are trying to read from file opened in WriteOnly mode ...
Think, this "problem" is not really difficult. Don't just copy-paste, you're supposed to be a programmer, right ?
In order to give you the next tip I'll need to write the code for you.

VitaliBR
15th February 2011, 13:59
Thanks

now worked :)

I did so:

QFile f("List.xml");
f.open(QIODevice::ReadWrite | QIODevice::Text);
QDomDocument doc;
doc.setContent( &f );
RemoveGroup(&doc,ui.comboBox->currentText());

A single doubt, I researched and tried but could not:
When he saves the new list in XML, it does not erase the old one, ie it saves the new list after the old list

<!DOCTYPE List><list>
<client>
<dns>google.com.br</dns>
<phone>(19)3632-9244</phone>
<name>Google</name>
</client>
<client>
<dns>uol.com.br</dns>
<phone>(16)3307-5496</phone>
<name>Uol</name>
</client>
<client>
<dns>terra.com.br</dns>
<phone>(21)3368-0422</phone>
<name>Terra</name>
</client>
</list>
<!DOCTYPE List><list>
<client>
<dns>uol.com.br</dns>
<phone>(16)3307-5496</phone>
<name>Uol</name>
</client>
<client>
<dns>terra.com.br</dns>
<phone>(21)3368-0422</phone>
<name>Terra</name>
</client>
</list>

VitaliBR
16th February 2011, 10:46
I tried using a doc.clear(), but did not work :(

stampede
16th February 2011, 12:12
Try it this way:
1) open file in ReadOnly mode, create your QDomDocument from it
2) close the file
3) do the processing of xml
4) open the same file again with WriteOnly, and Truncate flags set ( should clear previous content )
5) save new xml to file and close it

VitaliBR
16th February 2011, 13:28
Worked :D

Thanks guy!!