我正在使用MSXML解析器写出XML文件,我从这里下载了一个包装器:http://www.codeproject.com/KB/XML/JW_CXml.aspx。除了当我从代码创建一个新文档(因此不从文件加载和修改)时,效果很好,结果全部都在一个大的行中。我希望元素能够很好地缩进,以便我可以在文本编辑器中轻松阅读。
谷歌搜索显示许多人有同样的问题 - 大约在2001年左右被问到。回复通常会说“应用XSL转换”或“添加自己的空白节点”。特别是最后一个让我走了%(所以我希望在2008年有一个更简单的方法来实现漂亮的MSXML输出。所以我的问题是,那里,我该如何使用它?
答案 0 :(得分:4)
以下是已接受答案的修改版本,它将在内存中进行转换(仅在最后几行中进行更改,但我为了方便未来读者而发布整个块):
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;
}
答案 1 :(得分: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)));
}
答案 2 :(得分:1)
即使我的2美分在7年后到达,我认为问题仍然需要一个简单的答案,只需几行代码就可以了,这可以通过使用Visual C ++的#import
指令和本机C ++ COM支持库(提供智能指针并封装错误处理。)
请注意,与接受的答案一样,它不会尝试适合OP正在使用的CXml
类,而是显示核心思想。我还假设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
接口
wtlext有一个课程,您可以使用或从中推断出如何编写自己的课程。
另一个对我有用的简单解决方案是使用Ado Stream类:
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
函数显示了这一点:
#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
答案 3 :(得分:0)
除非库有格式选项,否则唯一的另一种方法是使用XSLT或外部漂亮的打印机(我认为htmltidy也可以做xml) 在codeproject lib中似乎没有选项,但你可以为MSXML指定一个XSLT样式表。
答案 4 :(得分:0)
我一会儿写了一个sed脚本,用于基本的xml缩进。如果所有其他方法都失败,您可以将它用作外部压头(将其保存到xmlindent.sed,并使用 sed -f xmlindent.sed&lt; filename&gt; 处理您的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)