Implement XmlPropertyListParser

This commit is contained in:
2015-02-19 18:52:17 +00:00
parent 018926d28a
commit 49d3484958
4 changed files with 212 additions and 4 deletions

View File

@@ -1,3 +1,10 @@
2015-02-19 Natalia Portillo <claunia@claunia.com>
* plist-cil.csproj:
* PropertyListParser.cs:
* XmlPropertyListParser.cs:
Implement XmlPropertyListParser
2015-02-19 Natalia Portillo <claunia@claunia.com>
* UID.cs:

View File

@@ -145,8 +145,7 @@ namespace Claunia.PropertyList
case TYPE_BINARY:
return BinaryPropertyListParser.Parse(f);
case TYPE_XML:
// TODO: Implement XMLPropertyListParser
//return XMLPropertyListParser.parse(f);
return XmlPropertyListParser.Parse(f);
case TYPE_ASCII:
return ASCIIPropertyListParser.Parse(f);
default:
@@ -164,8 +163,7 @@ namespace Claunia.PropertyList
case TYPE_BINARY:
return BinaryPropertyListParser.Parse(bytes);
case TYPE_XML:
// TODO: Implement XMLPropertyListParser
//return XMLPropertyListParser.parse(bytes);
return XmlPropertyListParser.Parse(bytes);
case TYPE_ASCII:
return ASCIIPropertyListParser.Parse(bytes);
default:

View File

@@ -0,0 +1,201 @@
// plist-cil - An open source library to parse and generate property lists for .NET
// Copyright (C) 2015 Natalia Portillo
//
// This code is based on:
// plist - An open source library to parse and generate property lists
// Copyright (C) 2014 Daniel Dreibrodt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Xml;
using System.Collections.Generic;
using System.IO;
namespace Claunia.PropertyList
{
/// <summary>
/// Parses XML property lists.
/// </summary>
/// @author Daniel Dreibrodt
public static class XmlPropertyListParser
{
/// <summary>
/// Parses a XML property list file.
/// </summary>
/// <param name="f">The XML property list file.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(FileInfo f) {
XmlDocument doc = new XmlDocument();
doc.Load(f.OpenRead());
return ParseDocument(doc);
}
/// <summary>
/// Parses a XML property list from a byte array.
/// </summary>
/// <param name="bytes">The byte array containing the property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(byte[] bytes) {
MemoryStream bis = new MemoryStream(bytes);
return Parse(bis);
}
/// <summary>
/// Parses a XML property list from an input stream.
/// </summary>
/// <param name="str">The input stream pointing to the property list's data.</param>
/// <returns>The root object of the property list. This is usually a NSDictionary but can also be a NSArray.</returns>
public static NSObject Parse(Stream str) {
XmlDocument doc = new XmlDocument();
doc.Load(str);
return ParseDocument(doc);
}
/// <summary>
/// Parses the XML document by generating the appropriate NSObjects for each XML node.
/// </summary>
/// <returns>The root NSObject of the property list contained in the XML document.</returns>
/// <param name="doc">The XML document.</param>
private static NSObject ParseDocument(XmlDocument doc) {
XmlDocumentType docType = doc.DocumentType;
if (docType == null) {
if (!doc.DocumentElement.Name.Equals("plist")) {
throw new XmlException("The given XML document is not a property list.");
}
} else if (!docType.Name.Equals("plist")) {
throw new XmlException("The given XML document is not a property list.");
}
XmlNode rootNode;
if (doc.DocumentElement.Name.Equals("plist")) {
//Root element wrapped in plist tag
List<XmlNode> rootNodes = FilterElementNodes(doc.DocumentElement.ChildNodes);
if (rootNodes.Count == 0) {
throw new PropertyListFormatException("The given XML property list has no root element!");
} else if (rootNodes.Count == 1) {
rootNode = rootNodes[0];
} else {
throw new PropertyListFormatException("The given XML property list has more than one root element!");
}
} else {
//Root NSObject not wrapped in plist-tag
rootNode = doc.DocumentElement;
}
return ParseObject(rootNode);
}
/// <summary>
/// Parses a node in the XML structure and returns the corresponding NSObject
/// </summary>
/// <returns>The corresponding NSObject.</returns>
/// <param name="n">The XML node.</param>
private static NSObject ParseObject(XmlNode n) {
if (n.Name.Equals("dict")) {
NSDictionary dict = new NSDictionary();
List<XmlNode> children = FilterElementNodes(n.ChildNodes);
for (int i = 0; i < children.Count; i += 2) {
XmlNode key = children[i];
XmlNode val = children[i + 1];
string keyString = GetNodeTextContents(key);
dict.Add(keyString, ParseObject(val));
}
return dict;
} else if (n.Name.Equals("array")) {
List<XmlNode> children = FilterElementNodes(n.ChildNodes);
NSArray array = new NSArray(children.Count);
for (int i = 0; i < children.Count; i++) {
array.SetValue(i, ParseObject(children[i]));
}
return array;
} else if (n.Name.Equals("true")) {
return new NSNumber(true);
} else if (n.Name.Equals("false")) {
return new NSNumber(false);
} else if (n.Name.Equals("integer")) {
return new NSNumber(GetNodeTextContents(n));
} else if (n.Name.Equals("real")) {
return new NSNumber(GetNodeTextContents(n));
} else if (n.Name.Equals("string")) {
return new NSString(GetNodeTextContents(n));
} else if (n.Name.Equals("data")) {
return new NSData(GetNodeTextContents(n));
} else if (n.Name.Equals("date")) {
return new NSDate(GetNodeTextContents(n));
}
return null;
}
/// <summary>
/// Returns all element nodes that are contained in a list of nodes.
/// </summary>
/// <returns>The sublist containing only nodes representing actual elements.</returns>
/// <param name="list">The list of nodes to search.</param>
private static List<XmlNode> FilterElementNodes(XmlNodeList list) {
List<XmlNode> result = new List<XmlNode>();
foreach (XmlNode child in result) {
if (child.NodeType == XmlNodeType.Element) {
result.Add(child);
}
}
return result;
}
/// <summary>
/// Returns a node's text content.
/// This method will return the text value represented by the node's direct children.
/// If the given node is a TEXT or CDATA node, then its value is returned.
/// </summary>
/// <returns>The node's text content.</returns>
/// <param name="n">The node.</param>
private static string GetNodeTextContents(XmlNode n) {
if (n.NodeType == XmlNodeType.Text || n.NodeType == XmlNodeType.CDATA) {
string content = n.Value; //This concatenates any adjacent text/cdata/entity nodes
if (content == null)
return "";
else
return content;
} else {
if (n.HasChildNodes) {
XmlNodeList children = n.ChildNodes;
foreach (XmlNode child in children) {
//Skip any non-text nodes, like comments or entities
if (child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA) {
string content = child.Value; //This concatenates any adjacent text/cdata/entity nodes
if (content == null)
return "";
else
return content;
}
}
return "";
} else {
return "";
}
}
} }
}

View File

@@ -30,6 +30,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -47,6 +48,7 @@
<Compile Include="ASCIIPropertyListParser.cs" />
<Compile Include="BinaryPropertyListParser.cs" />
<Compile Include="BinaryPropertyListWriter.cs" />
<Compile Include="XmlPropertyListParser.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>