xml/xsl to create msbuild files........MSB4097......and an xsl workarounds(??)

  • Thread starter Thread starter sloan
  • Start date Start date
S

sloan

<!-- The xml in question -->

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<Target Name="AllTargetsWrapper" xmlns="">
<Message Text="You just called the Target named 'AllTargetsWrapper'" />
</Target>
<!-- - - -->
<Target Name="Target1" xmlns="">
<Message Text="You just called the Target named 'Target1'" />
</Target>
<!-- - - -->
<Target Name="Target2" xmlns="">
<Message Text="You just called the Target named 'Target2'" />
</Target>
<!-- - - -->
<Target Name="Target3" xmlns="">
<Message Text="You just called the Target named 'Target3'" />
</Target>
<!-- - - -->
</Project>


<!-- -->




The backstory of this post is here:
https://connect.microsoft.com/Visua...mespace-attribute-even-if-its-the-correct-one

Basically, there are some msbuild/xml issues.
The wonderful error you get is:
error MSB4097: The element <Target> beneath element <Project> may not have a
custom XML namespace.


There are some suggestions at the site.
One is "write out the xml/reload it, then add elements".
The other one is "use the msbuild object library".
Neither is especially desirable.


I only recently found the issue at the connect.microsoft.com site......I put
in some heavy work creating some lightweight xml and then an xsl transform
sheet to create my msbuild project file.
Aka, I just did alot a work before I hit this monkey wrench. :<

At the top of this post ......there is the (resultant xml from my transform)
is currently what I'm stuck with.

The issue are these orphaned
xmlns=""
values.


Because of the bug......(outlined in the URL above)...

you cannot have this xml (below is a copy from the xml above):
<Target Name="AllTargetsWrapped" xmlns="">

AND you cannot do this:
<Target Name="AllTargetsWrapped"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">


The end result has to be:


<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<Target Name="AllTargetsWrapper"> <!-- Emphasis here because there is no
xmlns value -->
<Message Text="You just called the Target named 'AllTargetsWrapper'" />
</Target>
<!-- - - -->
<Target Name="Target1">
<Message Text="You just called the Target named 'Target1'" />
</Target>
<!-- - - -->
<Target Name="Target2">
<Message Text="You just called the Target named 'Target2'" />
</Target>
<!-- - - -->
<Target Name="Target3">
<Message Text="You just called the Target named 'Target3'" />
</Target>
<!-- - - -->
</Project>




==============

Here is a very basic (and does-not-do-anything-interesting) example of some
xml and xsl which creates the issue:

<!-- START XML -->

<?xml version="1.0" encoding="utf-8"?>
<root>
<demoTargets>
<demoTarget>
<targetName>AllTargetsWrapper</targetName>
</demoTarget>
<demoTarget>
<targetName>Target1</targetName>
</demoTarget>
<demoTarget>
<targetName>Target2</targetName>
</demoTarget>
<demoTarget>
<targetName>Target3</targetName>
</demoTarget>
</demoTargets>
</root>


<!-- END XML -->

<!-- START XSL-->

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:strip-space elements="*" />
<xsl:output method="xml" />
<!-- -->
<xsl:template match="/">
<!-- -->
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<xsl:comment> -- </xsl:comment>
<xsl:call-template name="CreateTargetsTemplate"></xsl:call-template>
<!-- -->
</Project>
<!-- -->
</xsl:template>
<!-- -->
<xsl:template name="CreateTargetsTemplate">
<!-- -->
<xsl:for-each select="//root/demoTargets/demoTarget">
<xsl:element name="Target">
<xsl:attribute name="Name">
<xsl:value-of select="./targetName" />
</xsl:attribute>
<xsl:element name="Message">
<xsl:attribute name="Text">You just called the Target named
'<xsl:value-of select="./targetName" />'</xsl:attribute>
</xsl:element>
</xsl:element>
<xsl:comment> -- </xsl:comment>
</xsl:for-each>
<!-- -->
</xsl:template>
<!-- -->
</xsl:stylesheet>


<!-- END XSL-->

<!-- START DESIRED RESULT -->

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<Target Name="AllTargetsWrapper" />
<!-- - - -->
<Target Name="Target1" />
<!-- - - -->
<Target Name="Target2" />
<!-- - - -->
<Target Name="Target3" />
<!-- - - -->
</Project>


<!-- END DESIRED RESULT -->






<!-- START RESULT1 THAT DOES NOT WORK -->

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<Target Name="AllTargetsWrapper" xmlns="" />
<!-- - - -->
<Target Name="Target1" xmlns="" />
<!-- - - -->
<Target Name="Target2" xmlns="" />
<!-- - - -->
<Target Name="Target3" xmlns="" />
<!-- - - -->
</Project>

<!-- END RESULT1 THAT DOES NOT WORK -->

<!-- START RESULT2 THAT DOES NOT WORK -->


<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<Target Name="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Target>
<!-- - - -->
<Target Name="Target1"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Target>
<!-- - - -->
<Target Name="Target2"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Target>
<!-- - - -->
<Target Name="Target3"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Target>
<!-- - - -->
</Project>

<!-- END RESULT2 THAT DOES NOT WORK -->



If you want to see this issue "in action"........then take the xml and xsl
above (the slimmed down version xml/xsl pair I have above)
Transform it, and put the resultant xml in a file called
"MSBuildXmlIssueTransformOutput.xml"

Create a .bat file
And put this in the .bat file

<!-- START BAT FILE -->

@echo off
ECHO Demonstrate MSBuild create Own Xml Issue:
ECHO .

@echo on

set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v3.5
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v2.0.50727

call %msBuildDir%\msbuild /target:AllTargetsWrapper
"MSBuildXmlIssueTransformOutput.xml" /p:Configuration=Release
/l:FileLogger,Microsoft.Build.Engine;logfile=MSBuildXmlIssueOutput.log

set msBuildDir=

<!-- END BAT FILE -->


You will see that you get MSBuild issues unless the xml is like "START
DESIRED RESULT" format above.


Any hope for this one? I've read the suggestions at connect.microsoft.com
and it just undermines my efforts I just put in.

Even if I have to perform two transformations, that is an option...........
I'm "ok" (skill-wise) with xsl, but thought I would post this issue to
people alot better at xsl than I am.


And I appreciate you looking, but comments along the lines of
"You don't have to use <xsl:element></xsl:element> , you can write it
shorter using ______________" are especially helpful on this one.
I'll rework the xsl to be trimmer if I find a workaround...I promise!



The engines I have available are.

DotNet Xml/Xsl Libraries, 3.5 Framework.
Saxon (in a pinch that is) ("C:\Program
Files\MSBuild\SaxonHE\bin\Transform.exe")
MSXML2.DOMDocument.6.0




Thanks for any help.


I'm probably gonna document some of this over on the connect.microsoft.com
site as well.......since I went to trouble of creating some samples.
 
Martin,

THANK YOU, it works just as you said.

I'm posting my basic-setup scenario xml and xsl so future googlers
(errrr......bingers) will find a basic and working example.

Again, thank you very much.



<!-- START XML -->

<?xml version="1.0" encoding="utf-8"?>
<root>
<demoTargets>
<demoTarget>
<targetName>AllTargetsWrapper</targetName>
</demoTarget>
<demoTarget>
<targetName>Target1</targetName>
</demoTarget>
<demoTarget>
<targetName>Target2</targetName>
</demoTarget>
<demoTarget>
<targetName>Target3</targetName>
</demoTarget>
</demoTargets>
</root>

<!-- END XML -->


<!-- START XSL THAT WORKS VIA INSTRUCTIONS IN PREVIOUS POST -->


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
version="2.0">
<!-- <xsl:strip-space elements="*" /> -->
<xsl:output method="xml" />
<xsl:variable name="AllTargetsWrapperConstant">
<xsl:value-of select="'AllTargetsWrapper'" />
</xsl:variable>
<!-- -->
<xsl:template match="/">
<!-- -->
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<xsl:comment> -- </xsl:comment>
<xsl:call-template name="CreateTargetsTemplate"></xsl:call-template>
<!-- -->
<xsl:comment> -- </xsl:comment>
</Project>
<!-- -->
</xsl:template>
<!-- -->
<xsl:template name="CreateTargetsTemplate">
<!-- -->
<xsl:comment> -- </xsl:comment>
<xsl:for-each select="//root/demoTargets/demoTarget">
<xsl:element name="Target">
<xsl:attribute name="Name">
<xsl:value-of select="./targetName" />
</xsl:attribute>
<xsl:element name="Message">
<xsl:attribute name="Text">You just called the Target named
'<xsl:value-of select="./targetName" />'</xsl:attribute>
</xsl:element>
<xsl:if test="targetName = $AllTargetsWrapperConstant">
<xsl:comment> The above special target name will call all targets
</xsl:comment>
<xsl:call-template
name="CreateAllTargetsSpecialTemplate"></xsl:call-template>
</xsl:if>
</xsl:element>
<xsl:comment> -- </xsl:comment>
</xsl:for-each>
<!-- -->
<xsl:comment> -- </xsl:comment>
</xsl:template>
<!-- -->
<xsl:template name="CreateAllTargetsSpecialTemplate">
<!-- -->
<xsl:for-each select="//root/demoTargets/demoTarget[targetName !=
$AllTargetsWrapperConstant]">
<xsl:element name="CallTarget">
<xsl:attribute name="Targets">
<xsl:value-of select="./targetName" />
</xsl:attribute>
</xsl:element>
<xsl:comment> -- </xsl:comment>
</xsl:for-each>
<!-- -->
</xsl:template>
<!-- -->
</xsl:stylesheet>



<!-- END XSL-->


=============================

<!-- START BAT FILE WHICH CALLS OUTPUT FROM ABOVE-->
<!-- Note, the output from above should be persisted in a file called
"MSBuildXmlIssueOutput.xml" -->


@echo off
ECHO Demonstrate MSBuild create Own Xml Issue:
ECHO .

@echo on

REM set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v3.5
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v2.0.50727

call %msBuildDir%\msbuild /target:AllTargetsWrapper
"MSBuildXmlIssueOutput.xml" /p:Configuration=Release
/l:FileLogger,Microsoft.Build.Engine;logfile=MSBuildXmlIssueOutput.log

set msBuildDir=

<!-- END BAT FILE WHICH CALLS OUTPUT FROM ABOVE-->


<!-- START Contents of MSBuildXmlIssueOutput.xml (after performing the
xml/xsl transformation above)(Just to show what I got and that Martin's
advice was spot-on -->

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AllTargetsWrapper"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- - - -->
<!-- - - -->
<Target Name="AllTargetsWrapper">
<Message Text="You just called the Target named 'AllTargetsWrapper'" />
<!-- The above special target name will call all targets -->
<CallTarget Targets="Target1" />
<!-- - - -->
<CallTarget Targets="Target2" />
<!-- - - -->
<CallTarget Targets="Target3" />
<!-- - - -->
</Target>
<!-- - - -->
<Target Name="Target1">
<Message Text="You just called the Target named 'Target1'" />
</Target>
<!-- - - -->
<Target Name="Target2">
<Message Text="You just called the Target named 'Target2'" />
</Target>
<!-- - - -->
<Target Name="Target3">
<Message Text="You just called the Target named 'Target3'" />
</Target>
<!-- - - -->
<!-- - - -->
<!-- - - -->
</Project>

<!-- END Contents of MSBuildXmlIssueOutput.xml (after performing the xml/xsl
transformation above) -->
 
Back
Top