XML Literals in VB.NET Code don't seem work with #if statements

218 views Asked by At

I have a vb.net project that uses an XML literal to configure the user interface navigation bar. The code looks something like this and has been working for many years.

Private ReadOnly _actionTreeXml As XElement =
<nodes>
    <node key="any" name="Top">
        <node key="log" name="***LOGIN***" type="everybody"></node>
        <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
        <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
        <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
        <node key="readme" name="Version Info" type="everybody"></node>
    </node>
</nodes>

I recently needed to have two builds of the project that differ slightly (don't want to pay for library code for many users). So I have one build where I #if out all the ui tools related to the barcode. This works great everwhere except in XML literals like this

#if USE_BAR_CODE=1
<node key="barcode" name="Barcode Entry"    ctrl="EditMfgEntry" type="mfg">  </node>
#end if

If I set USE_BAR_CODE to 0 I still get the xml literal inside the #if block, but everywhere in my code where I #if'ed regular VB source the code was not compiled.

This leads me to believe that the compliation process handles xml literals BEFORE #if statements. Am I missing something?

2

There are 2 answers

9
JohnyL On BEST ANSWER

May be not the solution at all, but as proverb says "A bad bush is better than the open field".

The main idea is to use processing instruction node. If element has processing instruction above it, then skip it, otherwise include it. This way you can control the "inclusiveness" of that element.

1) First, create extension method:

Module XmlExtentions
    <System.Runtime.CompilerServices.Extension>
    Function Filter(root_node As IEnumerable(Of XElement)) As IEnumerable(Of XElement)
        Return root_node.First().Elements().Where(
            Function(e)
                If e.PreviousNode Is Nothing Then Return True
                Return e.PreviousNode.NodeType <> Xml.XmlNodeType.ProcessingInstruction
            End Function)
    End Function
End Module

2. Query our XML:

Dim _actionTreeXml As XElement =
    <nodes>
        <node key="any" name="Top">
            <node key="log" name="***LOGIN***" type="everybody"></node>
            <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
            <?Skip-Element?>
            <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
            <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
            <node key="readme" name="Version Info" type="everybody"></node>
        </node>
    </nodes>

Dim elements = _actionTreeXml.<node>.Filter()
'// Do something...
elements.ToList().ForEach(Sub(e) Console.WriteLine(e))
6
Trevor On

Unfortunately no, you can't use directives like this in literals. Under the hood, the behavior is the same as the If, Then and Else statements. You can't put those directly in line the way you are, you have to wrap the code block to tell the compiler what to compile versus run time compile like the standard If, Then and Else statements. The statements within a conditional compilation block must be complete logical statements. For example, you cannot conditionally compile only the attributes of literals, functions etc...

So a quick solution is below to either include the node or not include it. This was tested as well and works just fine.

#If USE_BAR_CODE = 1 Then
    Private ReadOnly _actionTreeXml As XElement = <nodes>
                                                      <node key="any" name="Top">
                                                          <node key="log" name="***LOGIN***" type="everybody"></node>
                                                          <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
                                                          <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
                                                          <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
                                                          <node key="readme" name="Version Info" type="everybody"></node>
                                                      </node>
                                                  </nodes>
#Else
    Private ReadOnly _actionTreeXml As XElement = <nodes>
                                                      <node key="any" name="Top">
                                                          <node key="log" name="***LOGIN***" type="everybody"></node>
                                                          <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>                                                          
                                                          <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
                                                          <node key="readme" name="Version Info" type="everybody"></node>
                                                      </node>
                                                  </nodes>


#End If