Discussion:
Help - how to preserve XML Structure using C++ XSL Transform?
(too old to reply)
Nanker
2007-11-20 23:13:09 UTC
Permalink
I have the following XML:

<PrivateXML App="MyApp">
<Version version_no="1.0.0.0" version_date="Monday, March 26,
2007"/>
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker"/>
</PrivateDevice>
</PrivateDevices>
</PrivateXML>

and the following XSL:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">

<xsl:output media-type="text/xml" method="xml" encoding="utf-8"
indent="yes"/>

<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!-- Find the Version element and add the theName attribute -->
<xsl:template match="Version">
<xsl:copy>
<xsl:attribute name="theName">MyName</xsl:attribute>
<xsl:apply-templates select="@*|*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Using this pair with some C# transform applications, my results are
the following (which is what I'm looking for):

<PrivateXML App="MyApp">
<Version theName="MyName" version_no="1.0.0.0"
version_date="Monday, March 26, 2007" />
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker" />
</PrivateDevice>
</PrivateDevices>
</PrivateXML>

Using the following Visual C++ method:

bool PerformXslTransform(_bstr_t xmlSource, const bool
isSourceAFile,
IXSLProcessorPtr pProcessor, _bstr_t* transformedResult)
{
// Initialize all local variables
void *output = NULL;
XML2DocumentPtr pXml = NULL;
IStream *pOutStream;
bool success=false;

// load source XML and the XSL file
try
{
// Load the XML differently whether specified as a file or raw
XML
if(isSourceAFile)
{
pXml = pdocCreateFromUrl(xmlSource);
}
else
{
pXml = pdocCreateFromString(xmlSource);
}

// prepare Stream object to store results of transformation
CreateStreamOnHGlobal(NULL,TRUE,&pOutStream);
pProcessor->put_output(_variant_t(pOutStream));

// Attach to processor XML to transform, and do the
transoformation
pProcessor->put_input(_variant_t((IUnknown*)pXml));
pProcessor->transform();

//Get results of transformation
HGLOBAL hg = NULL;
pOutStream->Write((void const*)"\0",1,0);
GetHGlobalFromStream(pOutStream,&hg);
output = GlobalLock(hg);
*transformedResult = (const char*)output;
GlobalUnlock(hg);

success = true;
}
catch(...)
{
}

//release these components
if(pXml != NULL)
{
pXml.Release();
}

return success;
}

My results are instead the following:

<PrivateXML App="MyApp">
<Version theName="MyName" version_no="1.0.0.0"
version_date="Monday, March 26, 2007">
</Version>
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker">
</Speaker>
</PrivateDevice>
</PrivateDevices>
</PrivateXML>

I realize that these are equivalent, but these files in my environment
will possibly end up being edited by support teams, and I would rather
preserve the format:

<Speaker SpeakerID="0" name="MySpeaker"/>

instead of changing it to:

<Speaker SpeakerID="0" name="MySpeaker">
</Speaker>

Since the XSL provides the desired results using C#, I'm hoping that
there is something I'm missing with my C++ code to preserve the
element structure.

Can someone please provide some guidance as to how I can preserve this
structure using C++?

Thanks in advance
Joe Fawcett
2007-11-21 10:43:41 UTC
Permalink
Post by Nanker
<PrivateXML App="MyApp">
<Version version_no="1.0.0.0" version_date="Monday, March 26,
2007"/>
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker"/>
</PrivateDevice>
</PrivateDevices>
</PrivateXML>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output media-type="text/xml" method="xml" encoding="utf-8"
indent="yes"/>
<!-- Identity Transform -->
<xsl:copy>
</xsl:copy>
</xsl:template>
<!-- Find the Version element and add the theName attribute -->
<xsl:template match="Version">
<xsl:copy>
<xsl:attribute name="theName">MyName</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Using this pair with some C# transform applications, my results are
<PrivateXML App="MyApp">
<Version theName="MyName" version_no="1.0.0.0"
version_date="Monday, March 26, 2007" />
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker" />
</PrivateDevice>
</PrivateDevices>
</PrivateXML>
bool PerformXslTransform(_bstr_t xmlSource, const bool
isSourceAFile,
IXSLProcessorPtr pProcessor, _bstr_t* transformedResult)
{
// Initialize all local variables
void *output = NULL;
XML2DocumentPtr pXml = NULL;
IStream *pOutStream;
bool success=false;
// load source XML and the XSL file
try
{
// Load the XML differently whether specified as a file or raw
XML
if(isSourceAFile)
{
pXml = pdocCreateFromUrl(xmlSource);
}
else
{
pXml = pdocCreateFromString(xmlSource);
}
// prepare Stream object to store results of transformation
CreateStreamOnHGlobal(NULL,TRUE,&pOutStream);
pProcessor->put_output(_variant_t(pOutStream));
// Attach to processor XML to transform, and do the
transoformation
pProcessor->put_input(_variant_t((IUnknown*)pXml));
pProcessor->transform();
//Get results of transformation
HGLOBAL hg = NULL;
pOutStream->Write((void const*)"\0",1,0);
GetHGlobalFromStream(pOutStream,&hg);
output = GlobalLock(hg);
*transformedResult = (const char*)output;
GlobalUnlock(hg);
success = true;
}
catch(...)
{
}
//release these components
if(pXml != NULL)
{
pXml.Release();
}
return success;
}
<PrivateXML App="MyApp">
<Version theName="MyName" version_no="1.0.0.0"
version_date="Monday, March 26, 2007">
</Version>
<PrivateDevices>
<PrivateDevice DeviceID="1" Model="">
<Speaker SpeakerID="0" name="MySpeaker">
</Speaker>
</PrivateDevice>
</PrivateDevices>
</PrivateXML>
I realize that these are equivalent, but these files in my environment
will possibly end up being edited by support teams, and I would rather
<Speaker SpeakerID="0" name="MySpeaker"/>
<Speaker SpeakerID="0" name="MySpeaker">
</Speaker>
Since the XSL provides the desired results using C#, I'm hoping that
there is something I'm missing with my C++ code to preserve the
element structure.
Can someone please provide some guidance as to how I can preserve this
structure using C++?
Thanks in advance
Possibly setting to preserveWhitespace to true/false explicitly on the
document instance would help.
--
Joe Fawcett (MVP - XML)

http://joe.fawcett.name
Nanker
2007-11-21 15:08:15 UTC
Permalink
Thanks for the response - I tried that as well, but it provided the
same results.
Post by Joe Fawcett
Possibly setting to preserveWhitespace to true/false explicitly on the
document instance would help.
--
Joe Fawcett (MVP - XML)
Martin Honnen
2007-11-21 15:15:17 UTC
Permalink
Post by Nanker
Thanks for the response - I tried that as well, but it provided the
same results.
use preserveWhiteSpace = true before you load the XML input, then take
out the <xsl:output indent="true"/> that you have in your stylesheet
respectively use <xsl:output indent="false"/>.
--
Martin Honnen --- MVP XML
http://JavaScript.FAQTs.com/
Loading...