File: XmlElementExtensions.cs

package info (click to toggle)
mujoco 2.2.2-3.2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 39,796 kB
  • sloc: ansic: 28,947; cpp: 28,897; cs: 14,241; python: 10,465; xml: 5,104; sh: 93; makefile: 34
file content (167 lines) | stat: -rw-r--r-- 6,493 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Linq;
using System.Xml;
using UnityEngine;

namespace Mujoco {
// This class helps us manipulate MuJoCo-bound XML files. It is only intended to be used
// within the context of MuJoCo - elsewhere the preferred format is JSON.
public static class XmlElementExtensions {

  public static bool GetBoolAttribute(
      this XmlElement element, string name, bool defaultValue = false) {
    if (!element.HasAttribute(name)) {
      return defaultValue;
    }
    var strValue = element.GetAttribute(name);
    bool parsedValue;
    if (bool.TryParse(strValue, out parsedValue)) {
      return parsedValue;
    } else {
      throw new ArgumentException($"'{strValue}' is not a bool.");
    }
  }

  public static float GetFloatAttribute(
      this XmlElement element, string name, float defaultValue = 0.0f) {
    if (!element.HasAttribute(name)) {
      return defaultValue;
    }
    var strValue = element.GetAttribute(name);
    float parsedValue;
    if (float.TryParse(strValue, out parsedValue)) {
      return parsedValue;
    } else {
      throw new ArgumentException($"'{strValue}' is not a float.");
    }
  }

  // The MuJoCo parser is case-sensitive.
  public static T GetEnumAttribute<T>(
      this XmlElement element, string name, T defaultValue,
      bool ignoreCase = false) where T : struct, IConvertible {
    if (!typeof(T).IsEnum) {
      throw new ArgumentException("T must be an enumerated type.");
    }
    if (!element.HasAttribute(name)) {
      return defaultValue;
    }
    var strValue = element.GetAttribute(name);
    T parsedValue;
    if (Enum.TryParse<T>(strValue, ignoreCase, out parsedValue)) {
      return parsedValue;
    } else {
      throw new ArgumentException(
        $"Reading attribute {name}: '{strValue}' is not a value of enum {typeof(T)}.");
    }
  }

  public static string GetStringAttribute(
      this XmlElement element, string name, string defaultValue = null) {
    if (!element.HasAttribute(name)) {
      return defaultValue;
    }
    return element.GetAttribute(name);
  }

  public static T GetObjectReferenceAttribute<T>(
    this XmlElement mjcf, string attributeName) where T : MjComponent {
    var objectName = mjcf.GetStringAttribute(attributeName);
    if (string.IsNullOrEmpty(objectName)) {
      return null;
    }
    T foundObject = MjHierarchyTool.FindComponentOfTypeAndName<T>(objectName);
    if (foundObject == null) {
      throw new ArgumentException(
        $"Object {objectName} of type {typeof(T).ToString()} referred by {attributeName} " +
        "doesn't exist.");
    }
    return foundObject;
  }

  public static Vector2 GetVector2Attribute(
      this XmlElement element, string name, Vector2 defaultValue) {
    var defaultValues = new float[] {defaultValue.x, defaultValue.y};
    var components = element.GetFloatArrayAttribute(name, defaultValues, fillMissingValues: false);
    if (components.Length != 2) {
      throw new ArgumentException("Invalid Vector2 string representation.");
    }
    return new Vector2(components[0], components[1]);
  }

  public static Vector3 GetVector3Attribute(
      this XmlElement element, string name, Vector3 defaultValue) {
    var defaultValues = new float[] {
        defaultValue.x, defaultValue.y, defaultValue.z};
    var components = element.GetFloatArrayAttribute(name, defaultValues, fillMissingValues: false);
    if (components.Length != 3) {
      throw new ArgumentException("Invalid Vector3 string representation.");
    }
    return new Vector3(components[0], components[1], components[2]);
  }

  public static Quaternion GetQuaternionAttribute(
      this XmlElement element, string name, Quaternion defaultValue) {
    var mjDefault = new float[] {
        defaultValue.w, defaultValue.x, defaultValue.y, defaultValue.z };
    var components = element.GetFloatArrayAttribute(name, mjDefault, fillMissingValues: false);
    if (components.Length != 4) {
      throw new ArgumentException("Invalid Quaternion string representation.");
    }
    return new Quaternion(w:components[0], x:components[1], y:components[2], z:components[3]);
  }

  // Parses an array of whitespace separated floating points.
  //
  // Args:
  // . element: XmlElement that contains the attribute to be parsed.
  // . name: Name of the attribute to be parsed.
  // . defaultValue: An array of floats, or null. A default value to be returned in case the
  // the attribute is missing.
  // . fillMissingValues: If a default value was provided, and it has more components than the value
  // parsed from the attribute, the missing components will be copied from the defaultValue.
  public static float[] GetFloatArrayAttribute(
      this XmlElement element, string name, float[] defaultValue, bool fillMissingValues = true) {
    if (!element.HasAttribute(name)) {
      return defaultValue;
    }
    var strValue = element.GetAttribute(name);
    var components = strValue.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
    var resultLength = components.Length;
    if (fillMissingValues && defaultValue != null) {
      // If filling of the missing values was enabled, and a default value was provided,
      // allocate an array large enough to store a value of this length, in case when the parsed
      // value has fewer components.
      resultLength = Math.Max(resultLength, defaultValue.Length);
    }
    var result = new float[resultLength];
    for (var i = 0; i < components.Length; ++i) {
      float componentValue;
      if (float.TryParse(components[i], out componentValue)) {
        result[i] = componentValue;
      } else {
        throw new ArgumentException($"'{components[i]}' is not a float.");
      }
    }
    for (var i = components.Length; i < resultLength; ++i) {
      // Fill the missing values with defaults.
      result[i] = defaultValue[i];
    }
    return result;
  }
}
}