C++ & MSXML
-
hey everyone....
also, erst einmal ein paar dinge vorne weg. und zwar will ich 'ne xml datei mit hilfe von msxml (c++) auslesen. sprich auf knoten zugreifen und deren attribute etc. zurückgeben. aber am besten ich poste erstmal, was ich bereits habe:
- xml datei parsen (mit .dtd abgleichen)
- auf einzelnen knoten zugreifen und dessen attribut ausgeben#include "stdafx.h" #include <stdio.h> #import <msxml6.dll> using namespace MSXML2; #include <string> #include <iostream> using namespace std; inline void EVAL_HR( HRESULT _hr ) { if FAILED(_hr) throw(_hr); } int validate_file(char * m_file); void main() { char * file; int validation; do { cout<<"--------------------- Filenames ---------------------"<<endl<<endl; string filename_xml; cout<<"Xml - Filename (with extension):\n > "; cin >>filename_xml; file = new char[filename_xml.size()+1]; strcpy(file, filename_xml.c_str()); validation = validate_file(file); if (validation == 1) { int tmp; cout<<"\n\n---------------------- Options ----------------------"<<endl<<endl; cout<<" 1 - Try it again"<<endl; cout<<" 2 - Exit\n\n > "; cin >>tmp; if(tmp == 2) exit(0); else system("cls"); cout<<endl; } } while(validation != 0); IXMLDOMDocumentPtr objDOMDoc; EVAL_HR(CoInitialize(NULL)); EVAL_HR(objDOMDoc.CreateInstance("Msxml2.DOMDocument.6.0")); _variant_t varXml(file); _variant_t varOut((bool)TRUE); objDOMDoc->async = false; varOut = objDOMDoc->load(varXml); int end; do { try { string node_name; string path = "//"; string pathANDnode_name; cout<<"------------------- Reading Nodes -------------------"<<endl<<endl; cout<<"Node:\n > "; cin >>node_name; pathANDnode_name+=path; pathANDnode_name+=node_name; char * node = new char[pathANDnode_name.size()+1]; strcpy(node, pathANDnode_name.c_str()); cout<<endl; printf(objDOMDoc->documentElement->selectSingleNode(node)->text); string x = objDOMDoc->documentElement->selectSingleNode(node)->text; //attribute eines knotens printf(objDOMDoc->documentElement->selectSingleNode(node)->nextSibling->text); /* IXMLDOMElementPtr nodeBook; IXMLDOMAttributePtr nodeId; nodeBook = objDOMDoc->selectSingleNode("//seal_strip_diameter_right_Dx"); nodeId = nodeBook->getAttributeNode("German"); printf(nodeId->xml); */ cout<<endl<<endl; end = 1; } catch(...) { printf("Error 0/02 - Node doesn't exist.\n"); cout<<endl; end = 0; } if(end==0) { int tmp; cout<<"---------------------- Options ----------------------"<<endl<<endl; cout<<" 1 - Try it again"<<endl; cout<<" 2 - Exit\n\n > "; cin >>tmp; if(tmp == 2) { cout<<endl; exit(0); } else system("cls"); } } while(end != 1); CoUninitialize(); } //************************************************************************************************************************************************************* //*** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** FUNCTIONS *** //************************************************************************************************************************************************************* //*** VALIDATE XML FILE *** VALIDATE XML FILE *** VALIDATE XML FILE *** VALIDATE XML FILE *** VALIDATE XML FILE *** VALIDATE XML FILE *** VALIDATE XML FILE *** int validate_file(char * m_file) { try { IXMLDOMDocumentPtr objDOMDoc; EVAL_HR(CoInitialize(NULL)); EVAL_HR(objDOMDoc.CreateInstance("Msxml2.DOMDocument.6.0")); _variant_t varXml(m_file); _variant_t varOut((bool)TRUE); objDOMDoc->async = false; varOut = objDOMDoc->load(varXml); if ((bool)varOut == FALSE) throw(0); cout<<endl<<m_file<<" is valid."<<endl<<endl; return 0; } catch(...) { printf("\nError 0/01 - XML file isn't valid or doesn't exist."); return 1; } CoUninitialize(); }
soweit so gut. das funktioniert erstmal. jetzt hab ich aber eine xml datei, in der mehrere knoten gleichen namens drin sind...
link zur xml datei
http://www.3dg-fanbase.com/NC-Daten_76509_1.xmlprintf(objDOMDoc->documentElement->selectSingleNode(node)->text); springt jedoch immer zum ersten knoten, den es findet.
also angenommen ich suche in meiner xml datei den wert dieser zeile: <feed_type German="Fussform"> welche unter der id 4 liegt. sie gibt es allerdings auch unter id 3 oder id 5.meine frage jetzt: wie kann ich mit hilfe von msxml zwischen mehreren knoten suchen, die den gleichen namen haben?
in der hilfe find ich nicht wirklich was,.... und gegooglelt hab ich schon. also wäre schön, wenn jemand wirklich ahnung hat und mir helfen will.
thx matt
ps: nutze ms visual studio 6 professional
-
Du kannst eine LIste mehrer Knoten erhalten indem Du
IXMLDOMNodePtr pNode; BSTR bstrQuery; //... IXMLDOMNodeListPtr pNodeList = pNode->selectNodes(bstrQuery);
verwendest;
über die NodeList iteiert man dann so wie ich's Dir mit mit der AttributeList gezeigt hatte.Btw.; ein paar Kleinigkeiten:
Du vewendest (char*), und std::string; OLE muss daraus immer BSTR machen!
Schau Dir mal _bstr_t an!So wie Du das machst erzeugst Du immer 1001 Kopie von Strings - das ist inperformant.
Ich verwende BSTR, ::SysAllocString und ::SysFreeString wo immer möglich direkt; aber zumindest _bstr_t wär eine Verbesserung für Deinen Code!Ferner braucht man strcpy (oder besser _tcscpy) wirklich nicht mehr; und wenn dann bitte via <cstring> und <cstdio> wenn man <iostream> benutzt! Aber auch printf (oder besser _tprintf) braucht man nicht mit std::cout (std::wcout).
Warum verwendest Du MBCS statt UNICODE oder gleich TCHAR für beide Versionen?
Mein früheres Code-Beispiel war extra dafür ausgelegt...Grüsse
*this
P.S. objXYZ ist eher JavaScript oder VB Semantik; pDoc und pNode ist (V)C++ Konvention; mit C++ sind das (Smart)Pointer!
-
ok. thx soweit. ich musste mein prog zwar nochmal von grund auf neu machen, aber das "knoten-array" hab ich trotzdem gebraucht. naja und soweit funktionierts erst mal. was die kleinigkeiten wegen den datentypen und den "veralteten funktionen" wie strcpy betrifft... das werd ich am ende alles umstellen. bin erstmal froh, dass es soweit läuft.
eine frag aber hätte ich gleich noch. und zwar.... ich bin an einem punkt in meinem programm, an dem ich mehrere knoten nach einem übergeordneten knoten (in meinem fall "id" -> siehe xml datei) ausgeben will. nun ist aber das problem das ich hierzu unterschiedlich viele ebenen nach oben gehen muss. sprich ein einfaches "->parentNode" reicht nicht. manchmal brauch ich "->parentNode->parentNode" und manchmal "->parentNode->parentNode->parentNode". im moment hab ich das vorübergehend folgendermaßen gelöst:
try { printf(pNodeList->item[i]->parentNode->selectSingleNode("id")->text); } catch(...) { try { printf(pNodeList->item[i]->parentNode->parentNode->selectSingleNode("id")->text); } catch(...) { try { printf(pNodeList->item[i]->parentNode->parentNode->parentNode->selectSingleNode("id")->text); } catch(...) { printf(pNodeList->item[i]->parentNode->parentNode->parentNode->parentNode->selectSingleNode("id")->text); }
...naja. ist ja aber auch nicht im sinner der programmierung. hast du evtl. eine ahnung, wie man das besser machen könnte? mit schleife oder so...? weiß bloß nicht wie die schleife gehen soll....
naja... wenn meine problembeschreibung zu unverständlich ist, poste ich auch gerne nochmal mein aktuellen quelltext mit nem konkreten beispiel.
aber danke erstmal für die bisherige hilfe.
-
M@tt schrieb:
ok. thx soweit. ich musste mein prog zwar nochmal von grund auf neu machen, aber das "knoten-array" hab ich trotzdem gebraucht. naja und soweit funktionierts erst mal. was die kleinigkeiten wegen den datentypen und den "veralteten funktionen" wie strcpy betrifft... das werd ich am ende alles umstellen. bin erstmal froh, dass es soweit läuft.
eine frag aber hätte ich gleich noch. und zwar.... ich bin an einem punkt in meinem programm, an dem ich mehrere knoten nach einem übergeordneten knoten (in meinem fall "id" -> siehe xml datei) ausgeben will. nun ist aber das problem das ich hierzu unterschiedlich viele ebenen nach oben gehen muss. sprich ein einfaches "->parentNode" reicht nicht. manchmal brauch ich "->parentNode->parentNode" und manchmal "->parentNode->parentNode->parentNode".
Mach das lieber von oben nach unten:
IXMLDOMNodeListPtr pList; IXMLDOMNodePtr pNode; BSTR bstrTag = ::SysAllocString(_T("id")); // pList = pNode->getElementsByTagName(bstrTag); //... ::SysFreeString(bstrTag);
Auf alle Kindknoten der Knoten in pList müsste Deine Bedingung doch zureffen, oder? Btw "try-catch" verwendet man u.a. auch um zu tiefe Schachtelungen zu verwmeiden...
MSXML SDK 6.0:
Elements appear in the order encountered in a preorder traversal of this element's tree.
"Preorder traversal" heisst u.a. dass er den gesamten Teilbaum von pNode durchsucht; also musst Du nur hoch genug ansetzen.
Grüsse
*this
-
naja von oben nach unten ist jetzt mehr oder weniger zu spät, weil ich schon knapp 3 seiten quelltext auf die methode von "unten nach oben" geschrieben hab.
naja....
funktionieren tut's auch so. auch wenn's eben nich im sinne des programmierens ist.
-
M@tt schrieb:
naja von oben nach unten ist jetzt mehr oder weniger zu spät, weil ich schon knapp 3 seiten quelltext auf die methode von "unten nach oben" geschrieben hab.
Das kommt vor; es gibt im Extreme Programming
http://www.extremeprogramming.org/
die Grundregel "Refactor Mercilessly"
http://www.extremeprogramming.org/rules/refactor.html
Du bist mit Deinem Code imo in der genau der richtigen Phase dafür; Du kannst nicht erwarten dass Du mit einer für Dich neuen Konzeption anfängst und gleich druckreifen Code hervorzauberst.
Das kann niemand; obwohl es in Lehrbüchern (zum Wasserfallmodell) gerne so dargestellt wird...
Grüsse
*this
P.S. Btw was Du mit den gefundenen Knoten machst dürfte ja eh den Hauptteil ausmachen.
-
yap stimmt auch wieder.
hab zwar vorher noch nie was von xp gehört, aber so wie ich das verstanden hab ist das ja nich viel anders als trial & error. abgesehen davon, dass man "immer" ein funktionsfähiges produkt parat haben sollte, welches nach und nach verbessert wird.
anyway - thx 4 ur help.
-
hey Gast++
wollt mal fragen ob du evtl zu dem thema hier ne antwort weißt...in bezug auf irgendwelche funktionen in msxml
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1317032.html#1317032
thx schon mal
-
Halli Hallo nach langer Zeit....
ich wollt nicht unbedingt nen neuen Thread anfangen, aufgrund dessen weil es sich bei meiner Frage nur teilweise um C++ handelt.
Also ich wollt mal fragen ob man eigentlich auch MSXML 6.0 für C# verwenden kann? Sprich, dass ich meine ganzen Funktionen, die ich hier schon in einigen Threads für C++ gepostet habe, einfach nur umstellen brauch auf C#....?
thx für antworten