I was wondering if someone could help me out with an xml problem I'm having. I'm trying to parse this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map SYSTEM "http://mapeditor.org/dtd/1.0/map.dtd">
<map version="1.0" orientation="orthogonal" width="32" height="38" tilewidth="32" tileheight="32">
<properties>
<property name="Event" value="var MakeMapEvent = function(layer, mapPosition) { System.Console.Out.WriteLine(layer); }"/>
<property name="Starting Position" value="9,6"/>
</properties>
<tileset name="Void Tileset 2x - 4" firstgid="1" tilewidth="32" tileheight="32">
<image source="Void Tileset 2x - 4.png"/>
</tileset>
<tileset name="Untitled" firstgid="121" tilewidth="32" tileheight="32" spacing="32">
<image source="Collisions.png"/>
<tile id="0">
<properties>
<property name="Collision Layer" value="True"/>
</properties>
</tile>
</tileset>
<layer name="Tile Layer 2" width="32" height="38">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAAO3OMQqAMBBE0ai1Wqs3inVOoAfI/SvHQrCwMLBhFf6DafdvCMB3NVqrdU79Xhu00ak/abO2OPUB4MlufG8tbGfjfiz44WxvFfrXD2/+sO6n2w/R+PbffkhObQAAUN8BA9MHSAATAAA=
</data>
</layer>
<layer name="Tile Layer 1" width="32" height="38">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAAO1XPXPCMAzVT2Bj6VrajSvtCmVOuvKxQpOxBf7/UuvQu+hcS7Yp2fru3vmonbxnRbJVon/cA4+Bs8Cnyrl74SVwEfhaOecBvkHP/1I03ivnPO1FgpaHNnAqY4zGmbOAmMW0YrgRjV3lnAXELKYVQ8TLis+0QpvRiYdD4CTwS7R7Y30ux2r1z+KBn3uQkbUvxnr2uiI7PjX6HMujeJiL/ly0PykdY86thuwcK9XHd/wWD53o96J9ovR33oh+KsdyuRGvA9kDx+CZrns/kV+LW+Ode1n/kfGQqjmOwRtd9x7P8ftmGe6prH4tfY7BOrF3JtfEKsNDhT4lNDxyrnN+9M6IupiQXx9EQ72XajM4Py7O2NGQw/DkocSDjiHnx6eMbeL3mYYchqccEDPLh85jrrudMx5pyGF4KoUXi1wtARvhWnkq7UPYq3UP3lrPNX2IPjvAVYWHZWJ9rgY8bX6upd/fxfKAfNd3Y0kNxNq4e3HHNIUecB9pfe+O8rQbRfjIeUC+aX38rVa7lee28o6UB6yPUdL/QpscbY3Yw0StT73X8gboMyenHXvQPYL+trG29907tRes9bS1B90jYH1K28t79C+oj75AG9A9gqddspdczGOwlu4R0HPUamsPNf8npM7YW7VvAfJWU2vnzpu/wup7sG99XowBfR7qMXVejAGr70gB/nL3z1hgb/w9xszHWvwAqq1WOgATAAA=
</data>
</layer>
<layer name="Tile Layer 3" width="32" height="38">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAAGNgGAXUAiw4xBmBmAmImenoFmTAC8R8QMw/QPZLArEUEEuToXc07IgLu9FwIj+NjQLagtG0SVzaNKSDW0bBKBgFQw9oIbF1B8B+MyA2B2ILILakkR346gknIHYGYhcgdqWR/fjqCT8g9gfiABrZDQLDsQ1jBMTGA2w/CKsPkP22o24YNG6Ata8GKj2CwsAOiO0HyP5RgAkA54+5BwATAAA=
</data>
</layer>
<layer name="Tile Layer 4" width="32" height="38">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAAO3OMQ5AQABE0UWBAgUKFCgcyiW4f2ck2ykVE/Jf8uuZEAAAAPAXmzpitzMGvJGrQpWm/VZ1qjftz2pRq9pNH4CvSVSqMtN+pWrVmPYHNarJtI+nC1aVlIcAEwAA
</data>
</layer>
<objectgroup name="Object Group 4" width="0" height="0" x="-1"/>
<layer name="Collision Layer 1" width="32" height="38" x="-1">
<properties>
<property name="Collision Layer" value="True"/>
<property name="Test" value="True"/>
</properties>
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAAN2VSQ7EIAwE+fb8fq4R8lLtJYdYQgqyoRzcmHO+YT9jEN8k35tHvmxPb2zzo3OyfBt8xf/Myau/5XuDfy4fsQqfzFXtUd8k39N7dscn+B4vmpPciP68c810Ff2TsibKK/Mrvcrbq8qvmMLfsEn+9vkTNsnNmit7deIr97+bA+lh2bpODuobQvelsR2+WgdrTZVPNE1y8OrYuQNEG1kP6LJprPXtrZ18x55MqsuqFrP6UlZVi3cMYVNWtb9mbEW7hKvqUu0rGT/zq1rf5k/m0KnlFD8ad9wGvxo7qUPKV+/X1+0Pfn2cLQATAAA=
</data>
</layer>
</map>
The problem I'm having is I want to get the properties for the map. I can handle the properties of the layers/tilesets fine using List layernodes = layer.Descendants().ToList(); and List tilesetSubNodes = tileset.Descendants().ToList(); but if i do that for the map as a whole, I get everything within map, which will be wasteful to process. I tried using var properties = from x in localmap.Descendants("properties") select x; but that picks up the other properties sections as well. Is there a way to just get the properties group underneath map and none of the others? If it matters, here's how I'm currently parsing the file
public static TiledMap MakeMapFromXML(string xmlMapFile)
{
bool resettileproperties = false;
bool resetextendedproperties = false;
List<KeyValuePair<string, string>> extendedProperties = null;
Dictionary开发者_运维百科<int, KeyValuePair<string, string>> tileproperties = null;
TiledMap map = null;
string test;
Orientation orientation = Orientation.Orthogonal;
int mapwidth = 0, mapheight = 0, tilewidth = 0, tileheight = 0;
double version;
try
{
if (File.Exists(xmlMapFile))
{
doc = XDocument.Load(xmlMapFile);
string name = Path.GetFileNameWithoutExtension(xmlMapFile);
int firstGID = 0;
var maps = from x in doc.Descendants("map") select x;
string source = "";
foreach (var localmap in maps)
{
var tilesets = from x in localmap.Descendants("tileset") select x;
var layers = from x in localmap.Descendants("layer") select x;
var objectgroups = from x in localmap.Descendants("objectgroup") select x;
var properties = from x in localmap.Descendants("properties") select x;
Image tilesetSource = null;
List<XAttribute> mainmapatts = localmap.Attributes().ToList();
List<XElement> props = localmap.Descendants().ToList();
if (mainmapatts != null)
{
foreach (XAttribute attribute in mainmapatts)
{
switch (attribute.Name.LocalName)
{
case "version":
Double.TryParse(attribute.Value, out version);
break;
case "orientation":
Enum.TryParse<Orientation>(attribute.Value, out orientation);
break;
case "width":
Int32.TryParse(attribute.Value, out mapwidth);
break;
case "height":
Int32.TryParse(attribute.Value, out mapheight);
break;
case "tilewidth":
Int32.TryParse(attribute.Value, out tilewidth);
break;
case "tileheight":
Int32.TryParse(attribute.Value, out tileheight);
break;
}
}
}
if (orientation == Orientation.Orthogonal)
{
map = new TiledMap(name, mapwidth, mapheight, tilewidth, tileheight);
}
if (orientation == Orientation.Isometric)
{
//Not implemented yet
return null;
//map = new IsometricMap();
}
TileSet activetileset;
#region Load TileSets
foreach (var tileset in tilesets)
{
List<XAttribute> tilesetAtts = tileset.Attributes().ToList();
if (tilesetAtts != null)
{
foreach (XAttribute attribute in tilesetAtts)
{
switch (attribute.Name.LocalName)
{
case "firstgid":
int.TryParse(attribute.Value, out firstGID);
break;
case "name":
name = attribute.Value;
break;
case "tilewidth":
Int32.TryParse(attribute.Value, out tilewidth);
break;
case "tileheight":
Int32.TryParse(attribute.Value, out tileheight);
break;
}
}
}
XElement subnodeElement = null;
string key = "";
#region Load Tileset Subnodes
List<XElement> tilesetSubNodes = tileset.Descendants().ToList();
{
foreach (XElement subnode in tilesetSubNodes)
{
List<XAttribute> attributes = subnode.Attributes().ToList();
if (attributes != null)
{
switch (subnode.Name.LocalName)
{
case "image":
for (int i = 0; i < attributes.Count; i++)
{
if (String.Compare(attributes[i].Name.LocalName, "source", true) == 0)
{
source = attributes[i].Value;
}
}
break;
case "tile":
for (int i = 0; i < attributes.Count; i++)
{
if (String.Compare(attributes[i].Name.LocalName, "id", true) == 0)
{
key = attributes[i].Value;
}
}
//Need to add null check here
List<XElement> propertyNodes = subnode.Descendants().ToList();
if (propertyNodes != null)
{
foreach (XElement propertyNode in propertyNodes)
{
foreach (XElement subPropertyNode in propertyNode.DescendantNodes())
{
string keyname = null;
string keyvalue = null;
foreach (XAttribute attribute in ((XElement)subPropertyNode).Attributes())
{
if (String.Compare(attribute.Name.LocalName, "name") == 0)
{
keyname = attribute.Value;
}
else if (String.Compare(attribute.Name.LocalName, "value") == 0)
{
keyvalue = attribute.Value;
}
}
if (keyname != null && keyvalue != null)
{
if (tileproperties == null || resettileproperties)
{
tileproperties = new Dictionary<int, KeyValuePair<string, string>>();
resettileproperties = false;
tileproperties.Add(Int32.Parse(key), new KeyValuePair<string, string>(keyname, keyvalue));
}
}
}
}
}
break;
}
}
}
}
#endregion
if (File.Exists(source))// && !(name.ToLower().Contains("Collision") || name.ToLower().Contains("collision")))
{
tilesetSource = LoadTileSet(source);
if (tilesetSource != null)
{
activetileset = GenerateTileSet(tilesetSource, tilewidth, tileheight, name, firstGID);
if (!resettileproperties)
{
activetileset.AddTilePropertySet(tileproperties);
resettileproperties = true;
}
if (tileset != null && map != null)
map.AddTileSet(activetileset);
}
}
}
#endregion
#region Load Layers
Encoding encoding = Encoding.None;
Compression compression = Compression.None;
string datastring = "";
Layer locallayer;
bool CollisionLayer = false;
foreach (var layer in layers)
{
locallayer = null;
List<XAttribute> atts = layer.Attributes().ToList();
if (atts != null)
{
foreach (XAttribute attribute in atts)
{
switch (attribute.Name.LocalName)
{
case "name":
name = attribute.Value;
break;
case "width":
Int32.TryParse(attribute.Value, out mapwidth);
break;
case "height":
Int32.TryParse(attribute.Value, out mapheight);
break;
}
}
}
List<XElement> layernodes = layer.Descendants().ToList();
if (layernodes != null)
{
foreach (XElement node in layernodes)
{
switch (node.Name.LocalName)
{
case "data":
List<XAttribute> layerSubNodeAtts = node.Attributes().ToList();
if (layerSubNodeAtts != null)
{
foreach (XAttribute attribute in layerSubNodeAtts)
{
switch (attribute.Name.LocalName)
{
case "encoding":
Enum.TryParse<Encoding>(attribute.Value, out encoding);
break;
case "compression":
Enum.TryParse<Compression>(attribute.Value, out compression);
break;
}
}
}
datastring = node.Value;
if (encoding == Encoding.Base64 && compression == Compression.Gzip)
{
datastring = Utilities.GunzipAndDecodeData(datastring.Trim());
}
break;
case "properties":
List<XElement> layerSubNodes = node.Descendants().ToList();
if (layerSubNodes != null)
{
foreach (XElement subnodes in node.DescendantNodes())
{
string keyname = "";
string keyval = "";
foreach (XAttribute attribute in subnodes.Attributes())
{
bool valid = false;
if (attribute.NextAttribute != null && String.Compare(attribute.Value, "collision layer", true) == 0 && Boolean.TryParse(attribute.NextAttribute.Value, out valid) && valid)
{
CollisionLayer = true;
}
else
{
if (extendedProperties == null || resetextendedproperties)
{
extendedProperties = new List<KeyValuePair<string, string>>();
resetextendedproperties = false;
}
if (attribute.NextAttribute != null)
extendedProperties.Add(new KeyValuePair<string, string>(attribute.Value, attribute.NextAttribute.Value));
}
}
}
}
break;
}
}
}
if (CollisionLayer)
{
if (!resetextendedproperties)
{
locallayer = new CollisionLayer(name, mapwidth, mapheight, tilewidth, tileheight, datastring, extendedProperties);
resetextendedproperties = true;
}
else
{
locallayer = new CollisionLayer(name, mapwidth, mapheight, tilewidth, tileheight, datastring);
}
}
else
{
if (!resetextendedproperties)
{
locallayer = new Layer(name, mapwidth, mapheight, tilewidth, tileheight, datastring, extendedProperties);
resetextendedproperties = true;
}
else
{
locallayer = new Layer(name, mapwidth, mapheight, tilewidth, tileheight, datastring);
}
}
if (locallayer != null)
map.AddLayer(locallayer);
}
#endregion
foreach (var objectgroup in objectgroups)
{
//TODO
}
}
}
}
catch (Exception ex)
{
Console.Out.WriteLine("Error Parsing XML file " + ex.Message);
}
return map;
}
localmap.Element("properties").Elements("property") should work
Descendants includes children, grandchildren, great-grandchildren, etc. I think you want to use Elements("properties").Elements("property").
精彩评论