2009-07-20 2 views
12

У меня возникла проблема с десериализацией XML-файла с булевыми значениями. Исходные файлы XML, которые я десериализую, были созданы из приложения VB6, где все логические значения капитализируются (True, False). Когда я пытаюсь десериализации XML, я получаюXml Serialization vs. «True» и «False»

System.FormatException: The string 'False' is not a valid Boolean value. 

Есть ли способ сказать игнорировать случай с атрибутом?

ответ

5

Вы можете прочитать это значение как строку в поле строки, а затем иметь поле readoolly bool, в котором в нем есть оператор if, чтобы вернуть bool true или false.

Например (с помощью C#):

public bool str2bool(string str) 
{ 
    if (str.Trim().ToUpper() == "TRUE") 
     return true; 
    else 
     return false; 
} 

И вы можете использовать его в шаблоне:

<xsl:if test="user:str2bool($mystr)"> 
+1

Вы должны включить пример этого. Вероятно, у вас есть лучшее предложение, если вы это сделаете. –

1

Я не думаю, что есть. Вы можете сделать это строкой и выполнить сравнение (String.Compare), установив для параметра ignoreCase значение true.

3

Нет. Сериализатор XML работает с XML-схемой, а «True» и «False» не являются допустимыми логическими.

Вы можете использовать XML Transform для преобразования этих двух значений, или вы можете реализовать интерфейс IXmlSerializable и выполнить сериализацию и десериализацию самостоятельно.

+0

Вы правы Джон, вот что происходит, когда вы отвечаете перед обедом: \ .. но, честно говоря, ваше предложение Xml Transform потенциально может также преобразовать значение, которое не предназначено для булевых. –

+0

Собственно, нет. Я хотел бы, чтобы он явно ссылался только на атрибуты и/или на элементы, которые являются логическими. Я не хотел преобразовывать каждый атрибут. –

+0

Понял Джон. –

5

Вместо использования Верно или нет, используйте 0 или 1. Это будет работать Boolean.

4

На основе another stack overflow question вы можете сделать:

public class MySerilizedObject 
{ 
    [XmlIgnore] 
    public bool BadBoolField { get; set; } 

    [XmlElement("BadBoolField")] 
    public string BadBoolFieldSerialize 
    { 
     get { return this.BadBoolField ? "True" : "False"; } 
     set 
     { 
      if(value.Equals("True")) 
       this.BadBoolField = true; 
      else if(value.Equals("False")) 
       this.BadBoolField = false; 
      else 
       this.BadBoolField = XmlConvert.ToBoolean(value); 
     } 
    } 
} 
0

я наткнулся на тот же вопрос, и на основе ответа по Jman, я решил это так:

[XmlIgnore] 
    public bool BadBoolField { get; set; } 

    [XmlAttribute("badBoolField")] 
    public string BadBoolFieldSerializable 
    { 
     get 
     { 
      return this.BadBoolField.ToString(); 
     } 
     set 
     { 
      this.BadBoolField= Convert.ToBoolean(value); 
     } 
    } 

Имейте в виду, что это не обязательно с помощью спецификации XML/Serialization, но она работает хорошо и может обрабатывать широко распространенные значения преобразования (например, строку типа «True», «true», если вы замените ограничение на строку, которая также может обрабатывать числа).

0

Вот очень чистое решение, которое я придумал, основываясь на некоторых других вопросах, которые я нашел. Это намного чище, потому что тогда вам не нужно что-либо в вашем коде, кроме объявления типа, как SafeBool, как это:

public class MyXMLClass 
{ 
    public SafeBool Bool { get; set; } 
    public SafeBool? OptionalBool { get; set; } 
} 

вы можете даже сделать их необязательными, и все это просто работает. Эта структура SafeBool будет обрабатывать любые варианты вариантов true/false, yes/no или y/n. Он всегда будет сериализован как истинный/ложный, однако у меня есть другие структуры, подобные этому, которые я использую для сериализации конкретно как y/n или yes/no, когда эта схема требует (т.е. BoolYN, BoolYesNo structs).

using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Serialization; 

namespace AMain.CommonScaffold 
{ 
    public struct SafeBool : IXmlSerializable 
    { 
     private bool _value; 

     /// <summary> 
     /// Allow implicit cast to a real bool 
     /// </summary> 
     /// <param name="yn">Value to cast to bool</param> 
     public static implicit operator bool(
      SafeBool yn) 
     { 
      return yn._value; 
     } 

     /// <summary> 
     /// Allow implicit cast from a real bool 
     /// </summary> 
     /// <param name="b">Value to cash to y/n</param> 
     public static implicit operator SafeBool(
      bool b) 
     { 
      return new SafeBool { _value = b }; 
     } 

     /// <summary> 
     /// This is not used 
     /// </summary> 
     public XmlSchema GetSchema() 
     { 
      return null; 
     } 

     /// <summary> 
     /// Reads a value from XML 
     /// </summary> 
     /// <param name="reader">XML reader to read</param> 
     public void ReadXml(
      XmlReader reader) 
     { 
      var s = reader.ReadElementContentAsString().ToLowerInvariant(); 
      _value = s == "true" || s == "yes" || s == "y"; 
     } 

     /// <summary> 
     /// Writes the value to XML 
     /// </summary> 
     /// <param name="writer">XML writer to write to</param> 
     public void WriteXml(
      XmlWriter writer) 
     { 
      writer.WriteString(_value ? "true" : "false"); 
     } 
    } 
} 
+0

Посмотрите мой поиск и замените ответ. У вас много кода, который может быть лучше O (n), но иногда проблема просто требует решения Росса Перо. откройте капот и исправьте его. –

-1

Не беспокоить фиксации сломанной системы XML или борьба XmlSerializer, особенно для чего-то настолько тривиальным. Это не стоит. VB6 не вернется в ближайшее время.

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

xml = xml.Replace("True", "true").Replace("False", "false"); 

Это не будет выиграть награды за элегантность, но вы вернетесь на работу. Иногда вам просто нужно синее воротничок.

Что касается производительности, то вы повторяете строку O (n), но поскольку строки замены имеют одинаковую длину, для нее не требуются элементы движущейся строки. Более того, в зависимости от реализации, в модификации XmlSerializer могут быть большие накладные расходы.

+0

Вы предполагаете, что у вас есть легкий доступ к исходному HTML, чтобы иметь возможность выполнять поиск и замену, поэтому ваш ответ не является хорошим. Не говоря уже о том, большой ли пакет XML, ваш код будет генерировать огромную временную строку дважды, потому что строки в .net неизменяемы. –

+0

@ KendallBennett Ну, разве вы не считаете, что у него есть доступ к классам? Я никогда не видел случая, когда вы можете десериализовать данные, не имея доступа к входу xml. Если вы действительно обеспокоены производительностью и памятью, вам действительно следует избегать использования XmlSerializer, поскольку использует отражение, которое является одной из самых дорогих операций в .NET. В моем решении ничего не говорится о том, что он не может работать с потоковыми данными. Я хочу сказать, что наивные реализации иногда являются лучшими. Я узнал об этом. –

+0

Вы не можете просто заблокировать замену всего в XML, который является True с true и False с false. Это, безусловно, наивно и, конечно, собирается сломать некоторые ответы. Что, если в нем было что-то, что было чувствительным к регистру, и в нем было слово True? Вдруг это больше не работает ... –