0

解析する必要がある次の XML ドキュメントがあります。

...
<tx size_total="143">
  <type size="1" start_key="02">STX</type>
  <type size="3">Type</type>
  <type size="3" decimal="true">Serial</type>
  <type size="3" key="23 64 31">Function_Code</type>
  <type size="2" decimal="true">LIU</type>
  <type size="1">Status</type>
  <type size="2" repeat="64" binary ="true" binary_discard="2">Value</type>
  <type size="1">ETX</type>
  <type size="1">LRC</type>
...

解析用に次のコードを書きました。

XmlNodeList typeNodeList = txNode.SelectNodes(TYPE_NODE);
CommRuleContainer rc = new CommRuleContainer(funcNode.Attributes.GetNamedItem("name").Value,
                        txNode.Attributes.GetNamedItem("size_total").Value, funcNode.Attributes.GetNamedItem("id").Value);
foreach (XmlNode tNode in typeNodeList)
{
    int size = Convert.ToInt32(tNode.Attributes.GetNamedItem("size").Value);
    int repeat = Convert.ToInt32(tNode.Attributes.GetNamedItem("repeat").Value);
    int binary_discard = Convert.ToInt32(tNode.Attributes.GetNamedItem("binary_discard").Value);
    string start_key = tNode.Attributes.GetNamedItem("start_key").Value;
    string key = tNode.Attributes.GetNamedItem("key").Value;
    bool convert_decimal = false, convert_binary = false;
    if (tNode.Attributes.GetNamedItem("decimal").Value == "true")
                                convert_decimal = true;
    if (tNode.Attributes.GetNamedItem("binary").Value == "true")
                                convert_binary = true;
    rc.AddTypeDefinition(tNode.Value, size, repeat, binary_discard, convert_decimal, convert_binary);
}

存在しない特定の属性の値を取得しようとすると、コードは nullreferenceexception をスローします (IE: tNode.Attribute.GetNamedItem("repeat").value は、repeat 属性を持たないすべてのノードで失敗します)。特定の属性が存在するかどうかを確認する方法は?

また、上記のコードはまったくきれいではありません。上記のコードを整理する最良の方法は何ですか?

編集:属性から値を取得する前に、属性がnullかどうかを個別に確認できるアプローチを認識していますが、多くのif(またはネストされたif)を記述する必要があるため、コードが非常に汚く見えます

if (tNode.Attributes.GetNamedItem("decimal") != null)
   if (tNode.Attributes.GetNamedItem("decimal").Value == "true")
       convert_decimal = true;

より多くの属性を書かなければならない場合、これは長期的には問題になります。このための組織化されたアプローチをもっと知りたいです(おそらくXML属性を列挙できますか?わかりません。)

4

3 に答える 3

2

@nunespascal に同意します。ここに私が用意したコードがあります..彼は私よりも早く答えました..LOL:

static void Main(string[] args)
        {
            var serialized = @"
<tx size_total=""143""> 
  <type size=""1"" start_key=""02"">STX</type> 
  <type size=""3"">Type</type> 
  <type size=""3"" decimal=""true"">Serial</type> 
  <type size=""3"" key=""23 64 31"">Function_Code</type> 
  <type size=""2"" decimal=""true"">LIU</type> 
  <type size=""1"">Status</type> 
  <type size=""2"" repeat=""64"" binary =""true"" binary_discard=""2"">Value</type> 
  <type size=""1"">ETX</type> 
  <type size=""1"">LRC</type></tx>";
            var deserialized = serialized.XmlDeserialize<Tx>();
        }
    }

    [XmlRoot("tx")]
    public class Tx
    {
        [XmlAttribute("size_total")]
        public int TotalSize { get; set; }

        [XmlElement("type")]
        public List<TxType> Types { get; set; }

        public Tx()
        {
            Types = new List<TxType>();
        }
    }

    public class TxType
    {
        [XmlAttribute("size")]
        public string Size { get; set; }

        [XmlAttribute("decimal")]
        public bool IsDecimal { get; set; }

        [XmlAttribute("binary")]
        public bool IsBinary { get; set; }

        [XmlAttribute("start_key")]
        public string StartKey { get; set; }

        [XmlAttribute("key")]
        public string Key { get; set; }

        [XmlAttribute("repeat")]
        public int Repeat { get; set; }

        [XmlAttribute("binary_discard")]
        public int BinaryDiscard { get; set; }

        [XmlText]
        public string Value { get; set; }
    }

これがデシリアライズ用のヘルパー クラスです。

public static class StringExtensions
    {
        /// <summary>
        /// Deserializes the XML data contained by the specified System.String
        /// </summary>
        /// <typeparam name="T">The type of System.Object to be deserialized</typeparam>
        /// <param name="s">The System.String containing XML data</param>
        /// <returns>The System.Object being deserialized.</returns>
        public static T XmlDeserialize<T>(this string s)
        {
            var locker = new object();
            var stringReader = new StringReader(s);
            var reader = new XmlTextReader(stringReader);
            try
            {
                var xmlSerializer = new XmlSerializer(typeof(T));
                lock (locker)
                {
                    var item = (T)xmlSerializer.Deserialize(reader);
                    reader.Close();
                    return item;
                }
            }
            catch
            {
                return default(T);
            }
            finally
            {
                reader.Close();
            }
        }
    }

これで良いスタートが切れるはずです。幸運を。

于 2012-07-20T05:03:20.773 に答える
2
if(null != tNode.Attributes.GetNamedItem("repeat"))
   repeat = Convert.ToInt32(tNode.Attributes.GetNamedItem("repeat").Value);

アップデート

null 参照を取得しないことがわかったので、

これに対する最善の解決策は、.xml を使用して xml を逆シリアル化するクラスを作成することですXmlSerializer

カスタム シリアライゼーションに関するこの記事を参考にしてください。

XML シリアライゼーションを使用するには、最初に目的の XML マッピングを示す属性でデータ オブジェクトをマークアップする必要があります。これらの属性は System.Xml.Serialization 名前空間にあり、次のものが含まれます。

XmlRoot XML ファイルのルート要素の名前を指定します。デフォルトでは、XmlSerializer はクラスの名前を使用します。この属性は、クラス宣言に適用できます。

  • XmlElement プロパティまたはパブリック変数に使用する要素名を示します。既定では、XmlSerializer はプロパティまたはパブリック変数の名前を使用します。
  • XmlAttribute プロパティまたはパブリック変数を要素ではなく属性としてシリアル化する必要があることを示し、属性名を指定します。
  • XmlEnum 列挙値をシリアル化するときに使用するテキストを構成します。XmlEnum を使用しない場合は、列挙定数の名前が使用されます。
  • XmlIgnore プロパティまたはパブリック変数をシリアル化しないことを示します。
于 2012-07-20T04:28:33.733 に答える
1

さて、これは完全にテストされていないマッシュアップ関数、YMMV です。

static class XmlNodeExtensions {
    public static T GetAttrValue(this XmlNode node, string attrName) {
        return GetAttrValue(node, attrName, default(T));
    }
    public static T GetAttrValue(this XmlNode node, string attrName, T defaultValue) {
        var attr = node.Attributes.GetNamedItem(attrName);
        if (attr != null) {
            var value = attr.Value; 
            var tT = typeof(T);       // target Type
            if (tT.IsAssignableFrom(typeof(string)))
            {
                return (T)value;
            } else
            {
                var converter = TypeDescriptor.GetConverter(tT);
                if (converter.CanConvertFrom(typeof(string)))
                {
                    return (T)converter.ConvertFrom(value);
                } else
                {
                    throw new InvalidOperationException("No conversion possible");
                }
            }
        } else {
            return defaultValue;
        }
    }
}

.. それから ..

var id = node.GetAttrValue<int>("size");
var name = node.GetAttrValue("name", "no name!");
var titleOrNull = node.GetAttrValue<string>("title");

.. か何か。

于 2012-07-20T04:57:18.533 に答える