Evgeny Pokhilko's Weblog

Programmer's den

Effect of XML:Space=”preserve”

I was working with XAML created by Expression Blend. At runtime I noticed that a TextBlock moved on the right and one line down from the position it was in the designer. It took me some time to find the cause of the discrepancy. Below there is XAML of two TextBlock elements:

<TextBlock Height="17" VerticalAlignment="Top" xml:space="preserve"><Run xml:space="preserve">first line</Run></TextBlock>
<TextBlock Margin="0,22,0,0" Height="23" VerticalAlignment="Top">
    Second line
</TextBlock>

In the designer it looks like this:

When the application is running, the picture is different:

As you see, the second line moved on the right and one line down.

The only unusual part of XAML is the xml:space=”preserve” attribute, which is set at the first TextBlock and the Run elment inside it. This attribute says that all the indentation and spaces in XAML code should be saved at the time of rendering. But according to MSDN the attribute scope is only the content of the element where the attribute is defined. It’s defined at the first TextBlock and the contained Run element. If you remove the attribute from those elements everything renders correctly. But why does the attribute from the first TextBlock influences the second TextBlock. In the debugger I stopped the application and saved XAML of the “second line” TextBlock and it really had xml:space=”preserve” attribute. I assume it somehow came from the “first line” TextBlock.

It is apparently a bug in WPF. The bug only apears If you have more than one nested elements with the xml:space =”preserve” attribute defined at both. The next sibling element after those will have this attribute set to “preserve” implicitly.

The solution is simple: you need to set xml:space=”default” explicitly at the next element. So our XAML will be:

<TextBlock Height="17" VerticalAlignment="Top" xml:space="preserve"><Run xml:space="preserve">first line</Run></TextBlock>
<TextBlock Margin="0,22,0,0" Height="23" VerticalAlignment="Top" xml:space="default">
    Second line
</TextBlock>

Download the code for this post

June 23, 2008 Posted by | .NET, WPF | , , | 2 Comments

regular expressions for XML tags

Regular expressions are powerful and can substitute XML libraries for simple tasks. Say, you need to select all elements with a specific name from an XML file. Below is a sample doing that. The program reads XMLFile11, selects three different elements and prints them and their content to the console.

XMLFile1:

<?xml version="1.0" encoding="utf-8" ?>
<Main>
  <Item Name="item1"/>

  <Item Name ="item2">
    <Components>
      <Component/>
      <Component/>
      <Component Name="component10">
        <SubComponent/>
      </Component>
    </Components>

  </Item>
  <Item>
    <Item></Item>
    <Item></Item>
  </Item>
</Main>

C# code:

    class Program
    {
        public Program(string Xml)
        {
            _xml = Xml;
        }

        string _xml;

        void PrintTags(string tagName)
        {
            string expression =
                @"(<{0}\/>)|" + // gets <tagName/>
                @"(<{0}\s[^>]*?\/>)|" + //<tagName[space]BlaBla.../>
                @"(<{0}>[\s\S]*?<\/{0}\s*>)|" + //<tagName>BlaBla...</tagName>
                @"(<{0}\s[\s\S]*?>[\s\S]*?<\/{0}\s*>)"; //<tagName[space]BlaBla...>BlaBla...</tagName>

            Regex regex = new Regex(String.Format(expression, tagName));
            Match match = regex.Match(_xml);
            do
            {
                Console.WriteLine("tag: {0}", tagName);
                Console.WriteLine(match.Value);
                match = match.NextMatch();
            } while (match.Success);
        }

        void Run()
        {
            PrintTags("Item");
            PrintTags("Component");
            PrintTags("Components");
        }

        static void Main(string[] args)
        {
            Program program = new Program(File.ReadAllText("XMLFile1.xml"));
            program.Run();
            Console.Read();
        }
    }

I had to define expresions for four cases (see comments in the PrintTags method).
The following is the output:

Output:

tag: Item
<Item Name="item1"/>
tag: Item
<Item Name ="item2">
    <Components>
      <Component/>
      <Component/>
      <Component Name="component10">
        <SubComponent/>
      </Component>
    </Components>

  </Item>
tag: Component
<Component/>
tag: Component
<Component/>
tag: Component
<Component Name="component10">
        <SubComponent/>
      </Component>
tag: Components
<Components>
      <Component/>
      <Component/>
      <Component Name="component10">
        <SubComponent/>
      </Component>
    </Components>

However this code won’t work if XML file contains nested elements with identical names. See example below.

XML:

<Item>
    <Item></Item>
    <Item></Item>
</Item>

If you call the PrintTags method with “Item”, you will get <Item><Item></Item>. It happens because the regular expression doesn’t count opened and closed tags.

Code for this post

June 20, 2008 Posted by | .NET | , , | 2 Comments