diff --git a/src/API/MAL.php b/src/API/MAL.php
new file mode 100644
index 00000000..d6eb2199
--- /dev/null
+++ b/src/API/MAL.php
@@ -0,0 +1,49 @@
+
+ * @copyright 2015 - 2017 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.0
+ * @link https://github.com/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\API;
+
+use Aviat\AnimeClient\Enum\{AnimeWatchingStatus, MangaReadingStatus};
+
+/**
+ * Constants and mappings for the My Anime List API
+ */
+class MAL {
+ const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
+ const BASE_URL = 'https://myanimelist.net/api/';
+
+ public static function getIdToWatchingStatusMap()
+ {
+ return [
+ 1 => AnimeWatchingStatus::WATCHING,
+ 2 => AnimeWatchingStatus::COMPLETED,
+ 3 => AnimeWatchingStatus::ON_HOLD,
+ 4 => AnimeWatchingStatus::DROPPED,
+ 5 => AnimeWatchingStatus::PLAN_TO_WATCH
+ ];
+ }
+
+ public static function getIdToReadingStatusMap()
+ {
+ return [
+ 1 => MangaReadingStatus::READING,
+ 2 => MangaReadingStatus::COMPLETED,
+ 3 => MangaReadingStatus::ON_HOLD,
+ 4 => MangaReadingStatus::DROPPED,
+ 5 => MangaReadingStatus::PLAN_TO_READ
+ ];
+ }
+}
\ No newline at end of file
diff --git a/src/API/MAL/Enum/AnimeWatchingStatus.php b/src/API/MAL/Enum/AnimeWatchingStatus.php
new file mode 100644
index 00000000..b12e2657
--- /dev/null
+++ b/src/API/MAL/Enum/AnimeWatchingStatus.php
@@ -0,0 +1,30 @@
+
+ * @copyright 2015 - 2017 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.0
+ * @link https://github.com/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\API\MAL\Enum;
+
+use Aviat\Ion\Enum as BaseEnum;
+
+/**
+ * Possible values for watching status for the current anime
+ */
+class AnimeWatchingStatus extends BaseEnum {
+ const WATCHING = 'watching';
+ const COMPLETED = 'completed';
+ const ON_HOLD = 'onhold';
+ const DROPPED = 'dropped';
+ const PLAN_TO_WATCH = 'plantowatch';
+}
\ No newline at end of file
diff --git a/src/API/MAL/Enum/MangaReadingStatus.php b/src/API/MAL/Enum/MangaReadingStatus.php
new file mode 100644
index 00000000..edf82ddd
--- /dev/null
+++ b/src/API/MAL/Enum/MangaReadingStatus.php
@@ -0,0 +1,30 @@
+
+ * @copyright 2015 - 2017 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.0
+ * @link https://github.com/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\API\MAL\Enum;
+
+use Aviat\Ion\Enum as BaseEnum;
+
+/**
+ * Possible values for watching status for the current anime
+ */
+class MangaReadingStatus extends BaseEnum {
+ const READING = 'reading';
+ const COMPLETED = 'completed';
+ const ON_HOLD = 'onhold';
+ const DROPPED = 'dropped';
+ const PLAN_TO_READ = 'plantoread';
+}
\ No newline at end of file
diff --git a/src/API/XML.php b/src/API/XML.php
new file mode 100644
index 00000000..e8148737
--- /dev/null
+++ b/src/API/XML.php
@@ -0,0 +1,220 @@
+
+ * @copyright 2015 - 2017 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.0
+ * @link https://github.com/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\API;
+
+use DOMDocument, DOMNode, DOMNodelist;
+
+/**
+ * XML <=> PHP Array codec
+ */
+class XML {
+
+ /**
+ * XML representation of the data
+ *
+ * @var string
+ */
+ private $xml;
+
+ /**
+ * PHP array version of the data
+ *
+ * @var array
+ */
+ private $data;
+
+ /**
+ * XML constructor
+ */
+ public function __construct(string $xml = '', array $data = [])
+ {
+ $this->setXML($xml)->setData($data);
+ }
+
+ /**
+ * Serialize the data to an xml string
+ */
+ public function __toString(): string
+ {
+ return static::toXML($this->getData());
+ }
+
+ /**
+ * Get the data parsed from the XML
+ *
+ * @return array
+ */
+ public function getData(): array
+ {
+ return $this->data;
+ }
+
+ /**
+ * Set the data to create xml from
+ *
+ * @param array $data
+ * @return $this
+ */
+ public function setData(array $data): self
+ {
+ $this->data = $data;
+ return $this;
+ }
+
+ /**
+ * Get the xml created from the data
+ *
+ * @return string
+ */
+ public function getXML(): string
+ {
+ return $this->xml;
+ }
+
+ /**
+ * Set the xml to parse the data from
+ *
+ * @param string $xml
+ * @return $this
+ */
+ public function setXML(string $xml): self
+ {
+ $this->xml = $xml;
+ return $this;
+ }
+
+ /**
+ * Parse an xml document string to a php array
+ *
+ * @param string $xml
+ * @return array
+ */
+ public static function toArray(string $xml): array
+ {
+ $data = [];
+
+ // Get rid of unimportant text nodes by removing
+ // whitespace characters from between xml tags,
+ // except for the xml declaration tag, Which looks
+ // something like:
+ /* */
+ $xml = preg_replace('/([^\?])>\s+', '$1><', $xml);
+
+ $dom = new DOMDocument();
+ $dom->loadXML($xml);
+ $root = $dom->documentElement;
+
+ $data[$root->tagName] = [];
+
+ if ($root->hasChildNodes())
+ {
+ static::childNodesToArray($data[$root->tagName], $root->childNodes);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Transform the array into XML
+ *
+ * @param array $data
+ * @return string
+ */
+ public static function toXML(array $data): string
+ {
+ $dom = new DOMDocument();
+ $dom->encoding = 'UTF-8';
+
+ static::arrayPropertiesToXmlNodes($dom, $dom, $data);
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * Parse the xml document string to a php array
+ *
+ * @return array
+ */
+ public function parse(): array
+ {
+ $xml = $this->getXML();
+ $data = static::toArray($xml);
+ return $this->setData($data)->getData();
+ }
+
+ /**
+ * Transform the array into XML
+ *
+ * @return string
+ */
+ public function createXML(): string
+ {
+ return static::toXML($this->getData());
+ }
+
+ /**
+ * Recursively create array structure based on xml structure
+ *
+ * @param array &$root A reference to the current array location
+ * @param DOMNodeList $nodeList The current NodeList object
+ * @return void
+ */
+ private static function childNodesToArray(array &$root, DOMNodelist $nodeList)
+ {
+ $length = $nodeList->length;
+ for ($i = 0; $i < $length; $i++)
+ {
+ $el = $nodeList->item($i);
+ if (is_a($el->childNodes->item(0), 'DomText') || ( ! $el->hasChildNodes()))
+ {
+ $root[$el->nodeName] = $el->textContent;
+ }
+ else
+ {
+ $root[$el->nodeName] = [];
+ static::childNodesToArray($root[$el->nodeName], $el->childNodes);
+ }
+ }
+ }
+
+ /**
+ * Recursively create xml nodes from array properties
+ *
+ * @param DOMDocument $dom The current DOM object
+ * @param DOMNode $parent The parent element to append children to
+ * @param array $data The data for the current node
+ * @return void
+ */
+ private static function arrayPropertiesToXmlNodes(DOMDocument &$dom, DOMNode &$parent, array $data)
+ {
+ foreach($data as $key => $props)
+ {
+ $node = $dom->createElement($key);
+ if (is_array($props))
+ {
+ static::arrayPropertiesToXmlNodes($dom, $node, $props);
+ }
+ else
+ {
+ $tNode = $dom->createTextNode((string)$props);
+ $node->appendChild($tNode);
+ }
+
+ $parent->appendChild($node);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/API/XMLTest.php b/tests/API/XMLTest.php
new file mode 100644
index 00000000..50cebb37
--- /dev/null
+++ b/tests/API/XMLTest.php
@@ -0,0 +1,84 @@
+
+ * @copyright 2015 - 2017 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.0
+ * @link https://github.com/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Tests\API;
+
+use Aviat\AnimeClient\API\XML;
+use PHPUnit\Framework\TestCase;
+
+class XMLTest extends TestCase {
+
+ public function setUp()
+ {
+ $this->xml = file_get_contents(__DIR__ . '/../test_data/xmlTestFile.xml');
+ $this->expectedXml = file_get_contents(__DIR__ . '/../test_data/minifiedXmlTestFile.xml');
+
+ $this->array = [
+ 'entry' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => 42
+ ]
+ ],
+ 'episode' => '11',
+ 'status' => 'watching',
+ 'score' => '7',
+ 'storage_type' => '1',
+ 'storage_value' => '2.5',
+ 'times_rewatched' => '1',
+ 'rewatch_value' => '3',
+ 'date_start' => '01152015',
+ 'date_finish' => '10232016',
+ 'priority' => '2',
+ 'enable_discussion' => '0',
+ 'enable_rewatching' => '1',
+ 'comments' => 'Should you say something?',
+ 'tags' => 'test tag, 2nd tag'
+ ]
+ ];
+
+ $this->object = new XML();
+ }
+
+ public function testToArray()
+ {
+ $this->assertEquals($this->array, XML::toArray($this->xml));
+ }
+
+ public function testParse()
+ {
+ $this->object->setXML($this->xml);
+ $this->assertEquals($this->array, $this->object->parse());
+ }
+
+ public function testToXML()
+ {
+ $this->assertEquals($this->expectedXml, XML::toXML($this->array));
+ }
+
+ public function testCreateXML()
+ {
+ $this->object->setData($this->array);
+ $this->assertEquals($this->expectedXml, $this->object->createXML());
+ }
+
+ public function testToString()
+ {
+ $this->object->setData($this->array);
+ $this->assertEquals($this->expectedXml, $this->object->__toString());
+ $this->assertEquals($this->expectedXml, (string) $this->object);
+ }
+}
\ No newline at end of file
diff --git a/tests/test_data/minifiedXmlTestFile.xml b/tests/test_data/minifiedXmlTestFile.xml
new file mode 100644
index 00000000..c0490c7c
--- /dev/null
+++ b/tests/test_data/minifiedXmlTestFile.xml
@@ -0,0 +1,2 @@
+
+4211watching712.5130115201510232016201Should you say something?test tag, 2nd tag
diff --git a/tests/test_data/xmlTestFile.xml b/tests/test_data/xmlTestFile.xml
new file mode 100644
index 00000000..b37cf964
--- /dev/null
+++ b/tests/test_data/xmlTestFile.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 42
+
+
+ 11
+ watching
+ 7
+ 1
+ 2.5
+ 1
+ 3
+ 01152015
+ 10232016
+ 2
+ 0
+ 1
+ Should you say something?
+ test tag, 2nd tag
+
\ No newline at end of file