AutoCAD, XML и разделитель дробной части

    Недавно писал код, который, работая в составе плагина AutoCAD, должен был считывать данные из XML-файла, с последующей их обработкой в AutoCAD. В результате работы, в базе данных чертежа должен был появиться новый текстовый стиль, настроенный нужным образом. Привожу фрагмент XML-файла:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <!--Разработчик библиотеки-->
   3:  <Settings Description="Настройки программы." Notes = "">
   4:    <CommandGroups Description="Команды сгруппированы по типам создаваемых ими объектов. Тип создаваемого объекта указывается в атрибуте GroupName каждой группы." Notes="">
   5:      <CommandGroup GroupName="DText" TargetType ="Text" Namespace ="hwd" Description="Команды создания однострочного текста по ГОСТ 2.304-81 (Тип А)." Notes="">
   6:        <Command CommandName ="d2" Height="2,5" LineWeight="0,18" TextStyleKey="TxtStyle1" LayerKey ="Layer1" Description="Тип А прямой (уклон 0 градусов). Высота букв 2.5 мм, толщина линий 0.18 мм."/>
   7:        ...
   8:      </CommandGroup>
   9:    </CommandGroups>
  10:    <TextStyles Description="" Notes="Высота текста для стиля всегда программно устанавливается равной 0. По этой причине в настройках текстовых стилей отсутствует атрибут со значением высоты шрифта.">
  11:      <TextStyle Key="TxtStyle1" TextStyleName ="ГОСТ 2.304-81. Тип А прямой" FileFontName="mipgost.shx" Annotative="True" XScale="0,8" ObliqueAngle="0" 
  12:                 UseBigFont="False" MatchTextOrientationByLayout ="False" UpsideDown="False" Backwards="False" Vertical="False" BigFont="" Description=""/>
  13:      ...
  14:    </TextStyles>
  15:    <Layers Description="" Notes="">
  16:      <LayerRecord Key ="Layer1" LayerName ="Текст" Color="" Description="Слой, на котором должны располагаться объекты однострочного и многострочного текстов."/>
  17:    </Layers>
  18:  </Settings>

    Ряд атрибутов содержит десятичные значения, в которых десятичная часть отделена от целой символом "," (запятой). Разделитель должен совпадать с тем, который установлен на компьютере по умолчанию (Пуск => Панель управления => Дата, время, язык и региональные настройки => Язык и региональные стандарты => Вкладка "Региональные параметры" => Кнопка "Настройка" => Вкладка "Числа" => Поле "Разделитель целой и дробной части").

    Дело в том, что изначально я написал код в консольном приложении, с тем, чтобы затем через буфер обмена вставить его в код своей сборки, работающей под управлением AutoCAD. Так вот, в этом консольном приложении код отработал "на ура". Для понимания показываю его фрагмент, в котором добавил строку вывода на консоль интересующего меня значения:

Код C#

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Xml.Linq;
   6:   
   7:  namespace ConsoleTest
   8:  {
   9:      class Program
  10:      {
  11:          static void Main(string[] args)
  12:          {
  13:              //Уточняем группу, в которой следует искать информацию о команде
  14:              string groupName = "DText";
  15:              //Определяем имя ключа, хранящего информацию об интересующей нас команде
  16:              string cmdName = "d2";
  17:   
  18:                  //Получаем XML-объект, инкапсулирующий в себе информацию файла настроек
  19:                  XElement doc = XElement.Load("XmlData.xml");
  20:   
  21:                  //Группа команд создания объектов однострочного текста
  22:                  XElement cmdGroup = doc.Element("CommandGroups").Elements().Where(n => n.Attribute("GroupName").Value == groupName).First();
  23:   
  24:                  //Получаю запись с настройками команды
  25:                  XElement cmdRecord = cmdGroup.Elements().Where(n => n.Attribute("CommandName").Value == cmdName).First();
  26:   
  27:                  //Высота текста для команды
  28:                  string txtHeightValue = cmdRecord.Attribute("Height").Value;
  29:   
  30:                  //Получаю параметры текстового стиля
  31:                  //Сначала получаю имя ключа, по которому нужно будет искать текстовый стиль
  32:                  string txtStyleKey = cmdRecord.Attribute("TextStyleKey").Value;
  33:                  //Получаю объект текстового стиля
  34:                  XElement xTextStyle = doc.Element("TextStyles").Elements("TextStyle").Where(n => n.Attribute("Key").Value == txtStyleKey).First();
  35:   
  36:                  //Извлекаю информацию о текстовом стиле:
  37:   
  38:                  //1. Имя текстового стиля
  39:                  string txtStyleName = xTextStyle.Attribute("TextStyleName").Value;
  40:                  //2. Имя файла шрифта
  41:                  string fileFontName = xTextStyle.Attribute("FileFontName").Value;
  42:                  //3. Значение свойства аннотативности
  43:                  bool isAnnotative = Boolean.Parse(xTextStyle.Attribute("Annotative").Value);
  44:                  //4. Коэффициент сжатия                
  45:                  double xScale = Double.Parse(xTextStyle.Attribute("XScale").Value);           
  46:                  
  47:   
  48:              //ну и так далее...
  49:              
  50:              //Вывожу на консоль значение коэффициента сжатия
  51:                  Console.WriteLine("Коэффициент сжатия равен: {0}", xScale);
  52:              Console.Read();
  53:          }
  54:      }
  55:  }

Результат работы кода:

    Коэффициент сжатия равен: 0,8. Т.е. значение считывается правильное. После того, как весь код был написан, я скопировал его в исходники своего плагина, скомпилировал библиотеку и запустил её в режиме отладки. Код отработал без сообщений об ошибках, однако созданный мною текстовый стиль имел коэффициент сжатия не 0,8 (как это должно было бы быть), а 8

В процессе изучения проблемы выяснилось, что если в значениях атрибутов, имеющихся в XML-файле, заменить все разделители десятичной части с запятой на точку, то в AutoCAD код отрабатывает верно - создаваемый текстовый стиль имеет коэффициент сжатия 0,8 (как и нужно). Однако в консольном приложении код работать перестанет. Это навело меня на мысль, что в рамках своей сессии AutoCAD подменяет настоящее значение системного разделителя десятичной части на своё собственное - на точку.

Проверка предположения:

Проверил своё предположение, разместив в коде консольного приложения и в коде плагина AutoCAD такую строку кода:

   1:  string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

Результат проверки:

    В консольном приложении значение переменной decimalSeparator совпало с тем, которое установлено в системе - т.е. это была запятая. Однако находясь в теле кода загруженного в AutoCAD плагина, данная строка вернула точку.

Вывод:

    XML-документ может быть созданным различными людьми, в том числе и такими, которые, могут не являться пользователями AutoCAD, и, как следствие, не знать о подобной проблеме. Т.е. в одних XML-документах в качестве разделителя десятичной части может быть точка, а в других - запятая. С учётом этого, код, работающий в составе любого плагина AutoCAD, при взаимодействии с XML-файлом, обязательно должен производить замену существующего разделителя десятичной части на точку. 
Т.о. не будет иметь значение, какой разделитель десятичной части будет использоваться в XML-файле, поскольку в процессе его обработки всё будет приведено к единому знаменателю, озвученному системой AutoCAD.
Применительно к моему коду, чтобы результат его работы стал корректным, достаточно строку

 45:  double xScale = Double.Parse(xTextStyle.Attribute("XScale").Value);

слегка подправить, чтобы она стала такой:

 45:  double xScale = Double.Parse(xTextStyle.Attribute("XScale").Value.Replace(",", "."));

Теперь всё работает корректно.
Comments