2008-10-02 4 views
4

MSXML 파서를 사용하여 XML 파일을 작성했습니다. 여기에서 다운로드 한 래퍼와 함께 : http://www.codeproject.com/KB/XML/JW_CXml.aspx. 코드에서 새 문서를 만들 때 (파일에서로드하지 않고 수정하는 경우) 결과는 모두 큰 행으로 표시됩니다. 필자는 텍스트 편집기에서 텍스트를 쉽게 읽을 수 있도록 요소를 들여 쓰려고합니다.MSXML from C++ - 새롭게 작성된 문서를 인쇄/들여 쓰기가 편리합니다.

인터넷 검색은 같은 질문을 가진 많은 사람들을 보여줍니다. 2001 년경에 물었습니다. 회신은 일반적으로 'XSL 변환 적용'또는 '자신 만의 공백 노드 추가'라고 말합니다. 특히 마지막 하나는 나를 움직이게한다. (그래서 나는 2008 년에 MSXML 출력을보다 쉽게 ​​할 수 있기를 바라고있다. 나의 질문은 거기에있다. 어떻게 사용 하는가?

+0

에 오신 것을 환영합니다 :

void PrettySaveXmlDocument(MSXML2::IXMLDOMDocument* xmlDoc, const wchar_t* filePath) { ADODB::_StreamPtr stream(__uuidof(ADODB::Stream)); stream->Type = ADODB::adTypeBinary; stream->Open(vtMissing, ADODB::adModeUnknown, ADODB::adOpenStreamUnspecified, _bstr_t(), _bstr_t()); PrettyWriteXmlDocument(xmlDoc, IStreamPtr(stream)); stream->SaveToFile(filePath, ADODB::adSaveCreateOverWrite); } 

함께

가장 단순한 main 기능을 붙인 행동이 보여줍니다 지옥에. 6 가지 버전과 여러 언어에 대한 꼼꼼한 문서입니다. 대부분이 함께 작업하는 다른 버전입니다. 매크로 사용과 관련한 Microsoft의 사용 예제, 인류에 대한 모든 종류의 범죄. 나는 스타일 시트를 작성하고 스타일 시트를 사용하여 transformNodeToObject 함수를 적용하는 길로 가고있다. 불행히도 문서화되지 않은 예외가 던져지고있다. ... – Owl

답변

2

나는 웹에이 년 전에 발견,이보십시오.

여기
#include <msxml2.h> 

bool FormatDOMDocument (IXMLDOMDocument *pDoc, IStream *pStream) 
{ 

    // Create the writer 

    CComPtr <IMXWriter> pMXWriter; 
    if (FAILED (pMXWriter.CoCreateInstance(__uuidof (MXXMLWriter), NULL, CLSCTX_ALL))) 
    { 
     return false; 
    } 
    CComPtr <ISAXContentHandler> pISAXContentHandler; 
    if (FAILED (pMXWriter.QueryInterface(&pISAXContentHandler))) 
    { 
     return false; 
    } 
    CComPtr <ISAXErrorHandler> pISAXErrorHandler; 
    if (FAILED (pMXWriter.QueryInterface (&pISAXErrorHandler))) 
    { 
     return false; 
    } 
    CComPtr <ISAXDTDHandler> pISAXDTDHandler; 
    if (FAILED (pMXWriter.QueryInterface (&pISAXDTDHandler))) 
    { 
     return false; 
    } 

    if (FAILED (pMXWriter ->put_omitXMLDeclaration (VARIANT_FALSE)) || 
     FAILED (pMXWriter ->put_standalone (VARIANT_TRUE)) || 
     FAILED (pMXWriter ->put_indent (VARIANT_TRUE)) || 
     FAILED (pMXWriter ->put_encoding (L"UTF-8"))) 
    { 
     return false; 
    } 

    // Create the SAX reader 

    CComPtr <ISAXXMLReader> pSAXReader; 
    if (FAILED (pSAXReader.CoCreateInstance (__uuidof (SAXXMLReader), NULL, CLSCTX_ALL))) 
    { 
     return false; 
    } 

    if (FAILED (pSAXReader ->putContentHandler (pISAXContentHandler)) || 
     FAILED (pSAXReader ->putDTDHandler (pISAXDTDHandler)) || 
     FAILED (pSAXReader ->putErrorHandler (pISAXErrorHandler)) || 
     FAILED (pSAXReader ->putProperty (
     L"http://xml.org/sax/properties/lexical-handler", CComVariant (pMXWriter))) || 
     FAILED (pSAXReader ->putProperty (
     L"http://xml.org/sax/properties/declaration-handler", CComVariant (pMXWriter)))) 
    { 
     return false; 
    } 

    // Perform the write 

    return 
     SUCCEEDED (pMXWriter ->put_output (CComVariant (pStream))) && 
     SUCCEEDED (pSAXReader ->parse (CComVariant (pDoc))); 
} 
+0

대단한 일을합니다. 메모리 내에서이 작업을 수행하기 위해 몇 가지 수정 작업을했는데 주석에 맞지 않기 때문에 별도의 게시물에 게시 할 것입니다. – Roel

+0

본인 스스로 원본을 찾을 수 있었으면 좋겠습니다. 이것은 내 엉덩이를 저장했습니다. – Torlack

+0

http://discuss.com.cn/xml/86274.html에서 비슷한 것을 찾았습니다. 그 곳에서 '.GetInterfacePtr()'부분을 가져 왔습니다. 나는 중국어를 못하지만 페이지의 대부분을 이해할 수 없다. :) – Roel

0

라이브러리에 형식이 없다면 옵션을 누른 다음 유일한 다른 방법은 XSLT, 또는 외부 예쁜 프린터 (나는 htmltidy도 XML을 할 수있는 것)를 사용하는 것입니다 codeproject lib 옵션에 doen't 보이지 않지만 MSXML에 XSLT 스타일 시트를 지정할 수 있습니다.

+1

어리석은 사람. 실제로 codeproject lib에는 옵션이 없습니다. MSXML을 둘러싼 베어 본 래퍼입니다. 스타일 시트를 적용 할 수있는 쉬운 방법이 있나요? (XML을 디스크에 쓰지 않고 포맷 한 다음 다시 읽지 않고)? 스타일 시트는 어떻게 생겼을까요? – Roel

4

가 트란 것이다 허용 대답의 수정 된 버전입니다 나는 기본적인 XML 들여 쓰기 위해 잠시 다시 나오지도 스크립트를 작성했습니다

bool CXml::FormatDOMDocument(IXMLDOMDocument *pDoc) 
{ 
    // Create the writer 
    CComPtr <IMXWriter> pMXWriter; 
    if (FAILED (pMXWriter.CoCreateInstance(__uuidof (MXXMLWriter), NULL, CLSCTX_ALL))) { 
     return false; 
    } 
    CComPtr <ISAXContentHandler> pISAXContentHandler; 
    if (FAILED (pMXWriter.QueryInterface(&pISAXContentHandler))) { 
     return false; 
    } 
    CComPtr <ISAXErrorHandler> pISAXErrorHandler; 
    if (FAILED (pMXWriter.QueryInterface (&pISAXErrorHandler))) { 
     return false; 
    } 
    CComPtr <ISAXDTDHandler> pISAXDTDHandler; 
    if (FAILED (pMXWriter.QueryInterface (&pISAXDTDHandler))) { 
     return false; 
    } 

    if (FAILED (pMXWriter->put_omitXMLDeclaration (VARIANT_FALSE)) || 
     FAILED (pMXWriter->put_standalone (VARIANT_TRUE)) || 
     FAILED (pMXWriter->put_indent (VARIANT_TRUE)) || 
     FAILED (pMXWriter->put_encoding (L"UTF-8"))) 
    { 
     return false; 
    } 

    // Create the SAX reader 
    CComPtr <ISAXXMLReader> pSAXReader; 
    if (FAILED(pSAXReader.CoCreateInstance(__uuidof (SAXXMLReader), NULL, CLSCTX_ALL))) { 
     return false; 
    } 

    if (FAILED(pSAXReader->putContentHandler (pISAXContentHandler)) || 
     FAILED(pSAXReader->putDTDHandler (pISAXDTDHandler)) || 
     FAILED(pSAXReader->putErrorHandler (pISAXErrorHandler)) || 
     FAILED(pSAXReader->putProperty (L"http://xml.org/sax/properties/lexical-handler", CComVariant (pMXWriter))) || 
     FAILED(pSAXReader->putProperty (L"http://xml.org/sax/properties/declaration-handler", CComVariant (pMXWriter)))) 
    { 
     return false; 
    } 

    // Perform the write 
    bool success1 = SUCCEEDED(pMXWriter->put_output(CComVariant(pDoc.GetInterfacePtr()))); 
    bool success2 = SUCCEEDED(pSAXReader->parse(CComVariant(pDoc.GetInterfacePtr()))); 

    return success1 && success2; 
} 
+0

__uuidof (MXXMLWriter) 대신 __uuidof (MXXMLWriter40)를 사용하고 있음을 알게 될 때까지 처음에는이 문제를 해결하는 데 어려움이있었습니다. (코드는 "성공"했지만 들여 쓴 XML이되지는 않았습니다.) 나는 그것이 많은 차이를 만들었습니다. – Miral

+0

MSXML의 버전 관리는 항상 나를 움직이기 때문에 어떻게 작동하는지 잘 모릅니다. – Roel

+1

나를 위해이 ".GetInterfacePtr()"비트 작동하지 않았다. 나는 매우 비슷한 코드 스 니펫을 여기에서 찾지 못했다 : http://social.msdn.microsoft.com/forums/vstudio/en-US/e2e1ec90-bc92-4f70-96ec-94499e862402/add-indent-spaces-to-xml -nodes-with-ms-ixmldom –

0

: sform 인 - 메모리 (마지막 몇 줄의 변화하지만 미래의 독자의 편의를 위해 전체 블록을 게시하도록하겠습니다). 다른 모든 방법이 실패하면 외부 인 덴터로 사용할 수 있습니다 (xmlindent.sed에 저장하고 sed -f xmlindent.sed < 파일 이름 >)으로 xml을 처리하십시오. 당신은 cygwin이나 다른 posix 환경이 필요할 수도 있습니다.

:a 
/>/!N;s/\n/ /;ta 
s///g;s/^ *//;s/ */ /g 
/^<!--/{ 
:e 
/-->/!N;s/\n//;te 
s/-->/\n/;D; 
} 
/^<[?!][^>]*>/{ 
H;x;s/\n//;s/>.*$/>/;p;bb 
} 
/^<\/[^>]*>/{ 
H;x;s/\n//;s/>.*$/>/;s/^ //;p;bb 
} 
/^<[^>]*\/>/{ 
H;x;s/\n//;s/>.*$/>/;p;bb 
} 
/^<[^>]*[^\/]>/{ 
H;x;s/\n//;s/>.*$/>/;p;s/^/ /;bb 
} 
/</!ba 
{ 
H;x;s/\n//;s/ *<.*$//;p;s/[^ ].*$//;x;s/^[^<]*//;ba 
} 
:b 
{ 
s/[^ ].*$//;x;s/^<[^>]*>//;ba 
} 
Hrmp는, 탭이 깨진 것 같다

이 ... 당신은 복사 폐기물을 수 대신 여기에서 : XML indenting with sed(1)

0

는 심지어 내 2 센트 7 년 후에 나는이 생각에 도착 여기

소스입니다 질문은 여전히 ​​Visual C++의 #import 지시문과 네이티브 C++ COM 지원 라이브러리 (스마트 포인터 제공 및 오류 처리 캡슐화)를 사용하여 몇 줄의 코드로 간단하게 답변 할 가치가 있습니다.

대답은 대답과 마찬가지로 CXml 클래스에 맞지 않으므로 OP는 사용하지만 핵심 아이디어를 보여줍니다. 또한 msxml6라고 가정합니다. 어떤 스트림

void PrettyWriteXmlDocument(MSXML2::IXMLDOMDocument* xmlDoc, IStream* stream) 
{ 
    MSXML2::IMXWriterPtr writer(__uuidof(MSXML2::MXXMLWriter60)); 
    writer->encoding = L"utf-8"; 
    writer->indent = _variant_t(true); 
    writer->standalone = _variant_t(true); 
    writer->output = stream; 

    MSXML2::ISAXXMLReaderPtr saxReader(__uuidof(MSXML2::SAXXMLReader60)); 
    saxReader->putContentHandler(MSXML2::ISAXContentHandlerPtr(writer)); 
    saxReader->putProperty(PUSHORT(L"http://xml.org/sax/properties/lexical-handler"), writer.GetInterfacePtr()); 
    saxReader->parse(xmlDoc); 
} 

파일 스트림

예쁜 인쇄 당신이 IStream 인터페이스를 구현하여 자신을 쓸 수있는 파일 스트림 클래스의 작성을 필요로합니다.

나를 아도 스트림 클래스 활용되고 잘 작동하는 또 다른 간단한 해결책 :

#include <stdlib.h> 
#include <objbase.h> 
#include <comutil.h> 
#include <comdef.h> 
#include <comdefsp.h> 
#import <msxml6.dll> 
#import <msado60.tlb> rename("EOF", "EndOfFile") // requires: /I $(CommonProgramFiles)\System\ado 


void PrettyWriteXmlDocument(MSXML2::IXMLDOMDocument* xmlDoc, IStream* stream); 
void PrettySaveXmlDocument(MSXML2::IXMLDOMDocument* xmlDoc, const wchar_t* filePath); 


int wmain() 
{ 
    CoInitializeEx(nullptr, COINIT_MULTITHREADED); 

    try 
    { 
     MSXML2::IXMLDOMDocumentPtr xmlDoc(__uuidof(MSXML2::DOMDocument60)); 
     xmlDoc->appendChild(xmlDoc->createElement(L"root")); 

     PrettySaveXmlDocument(xmlDoc, L"xmldoc.xml"); 
    } 
    catch (const _com_error&) 
    { 
    } 

    CoUninitialize(); 

    return EXIT_SUCCESS; 
} 


// assume definitions of PrettyWriteXmlDocument and PrettySaveXmlDocument go here