{"id":103388,"date":"2020-01-31T07:00:00","date_gmt":"2020-01-31T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103388"},"modified":"2021-02-05T07:43:05","modified_gmt":"2021-02-05T15:43:05","slug":"20200131-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200131-00\/?p=103388","title":{"rendered":"The XAML hat rule: Understanding how it works and why it doesn&#8217;t"},"content":{"rendered":"<p>In <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/xaml-platform\/x-bind-markup-extension\"> the documentation for the <code>{x:Bind}<\/code> markup extension<\/a>, it says<\/p>\n<blockquote class=\"q\"><p>If the data source is a Dictionary or Map, then a property path can specify items in the collection by their string name. For example <b>&lt;TextBlock Text=&#8221;{x:Bind Players[&#8216;John Smith&#8217;]}&#8221; \/&gt;<\/b> will look for an item in the dictionary named &#8220;John Smith&#8221;. The name needs to be enclosed in quotes, and either single or double quotes can be used. <u>Hat (^) can be used to escape quotes in strings.<\/u> Its usually easiest to use alternate quotes from those used for the XAML attribute.<\/p><\/blockquote>\n<p>The use of the hat to escape quotes is also mentioned in <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/data-binding\/function-bindings\"> the documentation for functions in <code>x:Bind<\/code><\/a>, which says that an acceptable function argument is a<\/p>\n<blockquote class=\"q\"><p>Constant string enclosed in quotes \u2014 quotes are needed to designate it as a string. <u>Hat (^) can be used to escape quotes in strings.<\/u><\/p><\/blockquote>\n<p>Okay, we get the idea. The hat can be used to escape quotes in strings.<\/p>\n<p>Let&#8217;s try it. Let&#8217;s say I want to bind to the result of a function call whose parameter is a three-character string: <code>a\"b<\/code>.<\/p>\n<pre>&lt;TextBlock Text=\"{x:Bind Foo(\"a^\"b\")}\" \/&gt;\r\n&lt;TextBlock Text=\"{x:Bind Foo(^\"a^\"b^\")}\" \/&gt;\r\n<\/pre>\n<p>These don&#8217;t work.<\/p>\n<p>The first thing to understand is that XAML is still XML, so the markup is always parsed first by an XML parser. The XAML hat rule is applied <i>after<\/i> XML parsing has taken place. Therefore, the above two attempts don&#8217;t work because the result is not legal XML.<\/p>\n<p>Let&#8217;s try again, but escaping the quotation marks from XML parsing by using the <code>&amp;quot;<\/code> entity.<\/p>\n<pre>&lt;TextBlock Text=\"{x:Bind Foo(^&amp;quot;a^&amp;quot;b^&amp;quot;)}\" \/&gt;\r\n<\/pre>\n<p>This at least gets past the XML parser, but the XAML parser still doesn&#8217;t like it. After the XML parsing, the XAML parser sees the string<\/p>\n<pre>{x:Bind Foo(^\"a^\"b^\")}\r\n<\/pre>\n<p>The deal is that the hat is for escaping the quotation mark <i>inside<\/i> strings, not for escaping the quotation marks that <i>delimit<\/i> the string.<\/p>\n<p>Let&#8217;s try that again.<\/p>\n<pre>&lt;TextBlock Text=\"{x:Bind Foo(&amp;quot;a^&amp;quot;b&amp;quot;)}\" \/&gt;\r\n<\/pre>\n<p>After XML parsing, the string that gets passed to the XAML parser is<\/p>\n<pre>{x:Bind Foo(\"a^\"b\")}\r\n<\/pre>\n<p>Now we&#8217;re using the hat in the way the hat rule intended. The hat is escaping the embedded quotation mark. You can use it to escape a double-quote embedded inside a double-quote-delimited string. or to escape a single-quote embedded inside a single-quote-delimited string.<\/p>\n<p>Too bad it still doesn&#8217;t work. It passes the XAML parser, but you get a compiler error when it tries to compile the code generated by the XAML compiler. The specific code generation and resulting error depends on which language you&#8217;re using.<\/p>\n<pre>\/\/ C++\/WinRT code generation\r\n            ::winrt::hstring p0 = L\"a\"b\";\r\n\r\nerror C2001: newline in constant\r\n\r\n\/\/ C++\/CX code generation\r\n        ::Platform::String^ p0 = \"a\"b\";\r\n\r\nerror C2001: newline in constant\r\nerror C3688: invalid literal suffix 'b';\r\n             literal operator or literal operator template\r\n             'operator \"\"b' not found\r\nerror C2143: syntax error: missing ';' before 'Platform::String'\r\n\r\n\/\/ C# code generation\r\n                global::System.String p0 = \"a\"b\";\r\n\r\nerror CS1002: ; expected\r\nerror CS1002: ; expected\r\nerror CS1010: Newline in constant\r\nerror CS1002: ; expected\r\n\r\n' VB code generation\r\n                Dim p0 As Global.System.String = \"a\"b\"\r\n\r\nerror BC30648: String constants must end with a double quote.\r\n(and a ton of cascade errors)\r\n<\/pre>\n<p>The hat gets the XAML parser to understand your intention: Putting a double-quote inside a string. But then the XAML code generator drops the ball and fails to escape the embedded quote when emitting it.<\/p>\n<p>There are workarounds for this, some good and some bad.<\/p>\n<p>Since VB and the C-derived languages disagree on how the embedded quotation mark should be escaped, you cannot write language-independent markup to work around this. A bad workaround is to write language-specific markup, which kind of breaks the principle that XAML is language-independent. It also means that if the XAML compiler ever fixed the code generation bug, their bug fix would break your code.<\/p>\n<pre>&lt;!-- C++\/WinRT, C++\/CX, C# use a backslash to protect the quote --&gt;\r\n&lt;TextBlock Text=\"{x:Bind Foo(&amp;quot;a\\\\^&amp;quot;b&amp;quot;)}\"\/&gt;\r\n\r\n&lt;!-- VB doubles the quote --&gt;\r\n&lt;TextBlock Text=\"{x:Bind Foo(&amp;quot;a^&amp;quot;^&amp;quot;b&amp;quot;)}\"\/&gt;\r\n<\/pre>\n<p>A better workaround is to move the troublesome string to a property that can be defined by the implementation, and the implementation can produce the embedded quotation mark in a language-dependent way.<\/p>\n<pre>&lt;!-- add a property called AQuoteB whose value is a\"b --&gt;\r\n&lt;TextBlock Text=\"{x:Bind Foo(AQuoteB)}\"\/&gt;\r\n<\/pre>\n<p>All is not completely lost. At least the hat rule works for single-quotes:<\/p>\n<pre>&lt;TextBlock Text=\"{x:Bind Foo('a^'b')}\"\/&gt;\r\n<\/pre>\n<p>I asked the XAML compiler team if they could fix the code generation bug, but they explained that they couldn&#8217;t because it would be a breaking change. Specifically, it would break anybody who used the bad workaround above.<\/p>\n<p>The result of all this is that the XAML hat rule is useful only for single-quotes, not for double-quotes. The XAML hat rule lets you get a quotation mark <i>into<\/i> the XAML parser, but unfortunately, double-quotes can&#8217;t get back <i>out<\/i>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Finding the point in the parsing where the rule kicks in.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103388","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Finding the point in the parsing where the rule kicks in.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103388","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103388"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103388\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103388"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103388"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103388"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}