function testSerialize() { $dt = new \DateTime('2010-03-14 16:35', new \DateTimeZone('UTC')); $lastMod = new GetLastModified($dt); $doc = new \DOMDocument(); $root = $doc->createElement('d:getlastmodified'); $root->setAttribute('xmlns:d', 'DAV:'); $doc->appendChild($root); $server = new DAV\Server(); $lastMod->serialize($server, $root); $xml = $doc->saveXML(); /* $this->assertEquals( '<?xml version="1.0"?> <d:getlastmodified xmlns:d="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" b:dt="dateTime.rfc1123">' . HTTP\Util::toHTTPDate($dt) . '</d:getlastmodified> ', $xml); */ $this->assertEquals('<?xml version="1.0"?> <d:getlastmodified xmlns:d="DAV:">' . HTTP\Util::toHTTPDate($dt) . '</d:getlastmodified> ', $xml); $ok = false; try { GetLastModified::unserialize(DAV\XMLUtil::loadDOMDocument($xml)->firstChild, array()); } catch (DAV\Exception $e) { $ok = true; } if (!$ok) { $this->markTestFailed('Unserialize should not be supported'); } }
/** * @depends testSimple */ function testUnserializerBadData() { $xml = '<?xml version="1.0"?> <d:root xmlns:d="DAV:" xmlns:cal="' . CalDAV\Plugin::NS_CALDAV . '">' . '<cal:foo/>' . '</d:root>'; $dom = DAV\XMLUtil::loadDOMDocument($xml); $this->assertNull(ScheduleCalendarTransp::unserialize($dom->firstChild)); }
function parse($xml) { $xml = implode("\n", $xml); $dom = DAV\XMLUtil::loadDOMDocument($xml); $q = new AddressBookQueryParser($dom); $q->parse(); return $q; }
/** * @depends testSimple */ function testUnserializer() { $xml = '<?xml version="1.0"?> <d:root xmlns:d="DAV:" xmlns:cal="' . \Sabre\CalDAV\Plugin::NS_CALDAV . '">' . '<cal:comp name="VEVENT"/>' . '<cal:comp name="VJOURNAL"/>' . '</d:root>'; $dom = \Sabre\DAV\XMLUtil::loadDOMDocument($xml); $property = SupportedCalendarComponentSet::unserialize($dom->firstChild); $this->assertTrue($property instanceof SupportedCalendarComponentSet); $this->assertEquals(array('VEVENT', 'VJOURNAL'), $property->getValue()); }
/** * @depends testConstruct */ function testUnserialize() { $xml = '<?xml version="1.0"?> <d:anything xmlns:d="DAV:"><d:collection/><d:principal/></d:anything> '; $dom = DAV\XMLUtil::loadDOMDocument($xml); $resourceType = ResourceType::unserialize($dom->firstChild, array()); $this->assertEquals(array('{DAV:}collection', '{DAV:}principal'), $resourceType->getValue()); }
/** * Unserializes this property from a DOM Element * * This method returns an instance of this class. * It will only decode {DAV:}href values. * * @param \DOMElement $dom * @param array $propertyMap * @return DAV\Property\HrefList */ static function unserialize(\DOMElement $dom, array $propertyMap) { $hrefs = []; foreach ($dom->childNodes as $child) { if (DAV\XMLUtil::toClarkNotation($child) === '{DAV:}href') { $hrefs[] = $child->textContent; } } return new self($hrefs, false); }
/** * Unserializes this property from a DOM Element * * This method returns an instance of this class. * It will only decode tag values. * * @param \DOMElement $dom * @param array $propertyMap * @return \OCA\DAV\Connector\Sabre\TagList */ static function unserialize(\DOMElement $dom, array $propertyMap) { $tags = array(); foreach ($dom->childNodes as $child) { if (DAV\XMLUtil::toClarkNotation($child) === '{' . self::NS_OWNCLOUD . '}tag') { $tags[] = $child->textContent; } } return new self($tags); }
/** * Unserializes the DOMElement back into a Property class. * * @param \DOMElement $node * @return Property_SupportedCalendarComponentSet */ static function unserialize(\DOMElement $node) { $components = array(); foreach ($node->childNodes as $childNode) { if (DAV\XMLUtil::toClarkNotation($childNode) === '{' . CalDAV\Plugin::NS_CALDAV . '}comp') { $components[] = $childNode->getAttribute('name'); } } return new self($components); }
/** * This function handles the calendar-multiget REPORT. * * prefetch events into calendar container class, to avoid single lookup of events * * @param \DOMNode $dom * @return void */ public function calendarMultiGetReport($dom) { $properties = array_keys(\Sabre\DAV\XMLUtil::parseProperties($dom->firstChild)); $hrefElems = $dom->getElementsByTagNameNS('urn:DAV', 'href'); $filters = array('name' => 'VCALENDAR', 'comp-filters' => array(array('name' => 'VEVENT', 'prop-filters' => array()))); foreach ($hrefElems as $elem) { list($dirName, $baseName) = \Sabre\DAV\URLUtil::splitPath($elem->nodeValue); $filters['comp-filters'][0]['prop-filters'][] = array('name' => 'UID', 'text-match' => array('value' => $baseName)); } $node = $this->server->tree->getNodeForPath($this->server->getRequestUri()); $node->calendarQuery($filters); }
/** * Parses the request. * * @return void */ function parse() { $filter = $this->xpath->query('/cal:calendar-query/cal:filter'); if ($filter->length !== 1) { throw new \Sabre\DAV\Exception\BadRequest('Only one filter element is allowed'); } $compFilters = $this->parseCompFilters($filter->item(0)); if (count($compFilters) !== 1) { throw new \Sabre\DAV\Exception\BadRequest('There must be exactly 1 top-level comp-filter.'); } $this->filters = $compFilters[0]; $this->requestedProperties = array_keys(\Sabre\DAV\XMLUtil::parseProperties($this->dom->firstChild)); $expand = $this->xpath->query('/cal:calendar-query/dav:prop/cal:calendar-data/cal:expand'); if ($expand->length > 0) { $this->expand = $this->parseExpand($expand->item(0)); } }
function testUnserialize() { $source = '<?xml version="1.0"?> <d:root xmlns:d="DAV:"> <d:privilege> <d:write-properties /> </d:privilege> <d:privilege> <d:read /> </d:privilege> </d:root> '; $dom = DAV\XMLUtil::loadDOMDocument($source); $result = CurrentUserPrivilegeSet::unserialize($dom->firstChild, array()); $this->assertTrue($result->has('{DAV:}read')); $this->assertTrue($result->has('{DAV:}write-properties')); $this->assertFalse($result->has('{DAV:}bind')); }
/** * Unserializes the DOMElement back into a Property class. * * @param \DOMElement $node * @param array $propertyMap * @return ScheduleCalendarTransp */ static function unserialize(\DOMElement $node, array $propertyMap) { $value = null; foreach ($node->childNodes as $childNode) { switch (DAV\XMLUtil::toClarkNotation($childNode)) { case '{' . CalDAV\Plugin::NS_CALDAV . '}opaque': $value = self::OPAQUE; break; case '{' . CalDAV\Plugin::NS_CALDAV . '}transparent': $value = self::TRANSPARENT; break; } } if (is_null($value)) { return null; } return new self($value); }
/** * Parses the request. * * @return void */ function parse() { $limit = $this->xpath->evaluate('number(/card:addressbook-query/card:limit/card:nresults)'); if (is_nan($limit)) { $limit = null; } $filter = $this->xpath->query('/card:addressbook-query/card:filter'); // According to the CardDAV spec there needs to be exactly 1 filter // element. However, KDE 4.8.2 contains a bug that will encode 0 filter // elements, so this is a workaround for that. // // See: https://bugs.kde.org/show_bug.cgi?id=300047 if ($filter->length === 0) { $test = null; $filter = null; } elseif ($filter->length === 1) { $filter = $filter->item(0); $test = $this->xpath->evaluate('string(@test)', $filter); } else { throw new DAV\Exception\BadRequest('Only one filter element is allowed'); } if (!$test) { $test = self::TEST_ANYOF; } if ($test !== self::TEST_ANYOF && $test !== self::TEST_ALLOF) { throw new DAV\Exception\BadRequest('The test attribute must either hold "anyof" or "allof"'); } $propFilters = []; if (!is_null($filter)) { $propFilterNodes = $this->xpath->query('card:prop-filter', $filter); for ($ii = 0; $ii < $propFilterNodes->length; $ii++) { $propFilters[] = $this->parsePropFilterNode($propFilterNodes->item($ii)); } } $this->filters = $propFilters; $this->limit = $limit; $this->requestedProperties = array_keys(DAV\XMLUtil::parseProperties($this->dom->firstChild)); $this->test = $test; }
/** * HTTP REPORT method implementation * * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253) * It's used in a lot of extensions, so it made sense to implement it into the core. * * @param RequestInterface $request * @param ResponseInterface $response * @return bool */ function httpReport(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); $body = $request->getBodyAsString(); $dom = XMLUtil::loadDOMDocument($body); $reportName = XMLUtil::toClarkNotation($dom->firstChild); if ($this->server->emit('report', [$reportName, $dom, $path])) { // If emit returned true, it means the report was not supported throw new Exception\ReportNotSupported(); } // Sending back false will interupt the event chain and tell the server // we've handled this method. return false; }
/** * Unserializes the {DAV:}acl xml element. * * @param \DOMElement $dom * @param array $propertyMap * @return Acl */ static function unserialize(\DOMElement $dom, array $propertyMap) { $privileges = []; $xaces = $dom->getElementsByTagNameNS('urn:DAV', 'ace'); for ($ii = 0; $ii < $xaces->length; $ii++) { $xace = $xaces->item($ii); $principal = $xace->getElementsByTagNameNS('urn:DAV', 'principal'); if ($principal->length !== 1) { throw new DAV\Exception\BadRequest('Each {DAV:}ace element must have one {DAV:}principal element'); } $principal = Principal::unserialize($principal->item(0), $propertyMap); switch ($principal->getType()) { case Principal::HREF: $principal = $principal->getHref(); break; case Principal::AUTHENTICATED: $principal = '{DAV:}authenticated'; break; case Principal::UNAUTHENTICATED: $principal = '{DAV:}unauthenticated'; break; case Principal::ALL: $principal = '{DAV:}all'; break; } $protected = false; if ($xace->getElementsByTagNameNS('urn:DAV', 'protected')->length > 0) { $protected = true; } $grants = $xace->getElementsByTagNameNS('urn:DAV', 'grant'); if ($grants->length < 1) { throw new DAV\Exception\NotImplemented('Every {DAV:}ace element must have a {DAV:}grant element. {DAV:}deny is not yet supported'); } $grant = $grants->item(0); $xprivs = $grant->getElementsByTagNameNS('urn:DAV', 'privilege'); for ($jj = 0; $jj < $xprivs->length; $jj++) { $xpriv = $xprivs->item($jj); $privilegeName = null; for ($kk = 0; $kk < $xpriv->childNodes->length; $kk++) { $childNode = $xpriv->childNodes->item($kk); if ($t = DAV\XMLUtil::toClarkNotation($childNode)) { $privilegeName = $t; break; } } if (is_null($privilegeName)) { throw new DAV\Exception\BadRequest('{DAV:}privilege elements must have a privilege element contained within them.'); } $privileges[] = ['principal' => $principal, 'protected' => $protected, 'privilege' => $privilegeName]; } } return new self($privileges); }
/** * Unserializes this property from a DOM Element * * This method returns an instance of this class. * It will only decode {DAV:}href values. For non-compatible elements null will be returned. * * @param \DOMElement $dom * @param array $propertyMap * @return DAV\Property\Href */ static function unserialize(\DOMElement $dom, array $propertyMap) { if ($dom->firstChild && DAV\XMLUtil::toClarkNotation($dom->firstChild) === '{DAV:}href') { return new self($dom->firstChild->textContent, false); } }
/** * Unserializes a DOM element into a ResourceType property. * * @param \DOMElement $dom * @return DAV\Property\ResourceType */ public static function unserialize(\DOMElement $dom) { $value = array(); foreach ($dom->childNodes as $child) { $value[] = DAV\XMLUtil::toClarkNotation($child); } return new self($value); }
/** * Unserializes the {DAV:}current-user-privilege-set element. * * @param \DOMElement $node * @param array $propertyMap * @return CurrentUserPrivilegeSet */ static function unserialize(\DOMElement $node, array $propertyMap) { $result = []; $xprivs = $node->getElementsByTagNameNS('urn:DAV', 'privilege'); for ($jj = 0; $jj < $xprivs->length; $jj++) { $xpriv = $xprivs->item($jj); $privilegeName = null; for ($kk = 0; $kk < $xpriv->childNodes->length; $kk++) { $childNode = $xpriv->childNodes->item($kk); if ($t = DAV\XMLUtil::toClarkNotation($childNode)) { $privilegeName = $t; break; } } $result[] = $privilegeName; } return new self($result); }
/** * This method parses the PROPFIND request and returns its information * * This will either be a list of properties, or an empty array; in which case * an {DAV:}allprop was requested. * * @param string $body * @return array */ public function parsePropFindRequest($body) { // If the propfind body was empty, it means IE is requesting 'all' properties if (!$body) { return array(); } $dom = XMLUtil::loadDOMDocument($body); $elem = $dom->getElementsByTagNameNS('urn:DAV', 'propfind')->item(0); return array_keys(XMLUtil::parseProperties($elem)); }
/** * parsePrincipalPropertySearchReportRequest * * This method parses the request body from a * {DAV:}principal-property-search report. * * This method returns an array with two elements: * 1. an array with properties to search on, and their values * 2. a list of propertyvalues that should be returned for the request. * * @param \DOMDocument $dom * @return array */ protected function parsePrincipalPropertySearchReportRequest($dom) { $httpDepth = $this->server->getHTTPDepth(0); if ($httpDepth !== 0) { throw new DAV\Exception\BadRequest('This report is only defined when Depth: 0'); } $searchProperties = []; $applyToPrincipalCollectionSet = false; $test = $dom->firstChild->getAttribute('test') === 'anyof' ? 'anyof' : 'allof'; // Parsing the search request foreach ($dom->firstChild->childNodes as $searchNode) { if (DAV\XMLUtil::toClarkNotation($searchNode) == '{DAV:}apply-to-principal-collection-set') { $applyToPrincipalCollectionSet = true; } if (DAV\XMLUtil::toClarkNotation($searchNode) !== '{DAV:}property-search') { continue; } $propertyName = null; $propertyValue = null; foreach ($searchNode->childNodes as $childNode) { switch (DAV\XMLUtil::toClarkNotation($childNode)) { case '{DAV:}prop': $property = DAV\XMLUtil::parseProperties($searchNode); reset($property); $propertyName = key($property); break; case '{DAV:}match': $propertyValue = $childNode->textContent; break; } } if (is_null($propertyName) || is_null($propertyValue)) { throw new DAV\Exception\BadRequest('Invalid search request. propertyname: ' . $propertyName . '. propertvvalue: ' . $propertyValue); } $searchProperties[$propertyName] = $propertyValue; } return [$searchProperties, array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)), $applyToPrincipalCollectionSet, $test]; }
/** * This method parses the PROPFIND request and returns its information * * This will either be a list of properties, or an empty array; in which case * an {DAV:}allprop was requested. * * @param string $body * @return array */ function parsePropFindRequest($body) { // If the propfind body was empty, it means IE is requesting 'all' properties if (!$body) { return []; } $dom = XMLUtil::loadDOMDocument($body); $elem = $dom->getElementsByTagNameNS('urn:DAV', 'propfind')->item(0); if (is_null($elem)) { throw new Exception\UnsupportedMediaType('We could not find a {DAV:}propfind element in the xml request body'); } return array_keys(XMLUtil::parseProperties($elem)); }
/** * @expectedException Sabre\DAV\Exception\BadRequest */ function testUnserializeUnknown() { $xml = '<?xml version="1.0"?> <d:principal xmlns:d="DAV:">' . ' <d:foo />' . '</d:principal>'; $dom = DAV\XMLUtil::loadDOMDocument($xml); Principal::unserialize($dom->firstChild, array()); }
/** * @expectedException Sabre\DAV\Exception */ function testUnserializeNoStatus() { $xml = '<?xml version="1.0"?> <d:root xmlns:d="DAV:" xmlns:cal="' . CalDAV\Plugin::NS_CALDAV . '" xmlns:cs="' . CalDAV\Plugin::NS_CALENDARSERVER . '"> <cs:user> <d:href>mailto:user1@example.org</d:href> <!-- <cs:invite-accepted/> --> <cs:access> <cs:read-write/> </cs:access> </cs:user> </d:root>'; $doc2 = DAV\XMLUtil::loadDOMDocument($xml); $outputProperty = Invite::unserialize($doc2->firstChild); }
/** * This function handles the addressbook-multiget REPORT. * * This report is used by the client to fetch the content of a series * of urls. Effectively avoiding a lot of redundant requests. * * @param \DOMNode $dom * @return void */ function addressbookMultiGetReport($dom) { $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)); $hrefElems = $dom->getElementsByTagNameNS('urn:DAV', 'href'); $propertyList = []; $uris = []; foreach ($hrefElems as $elem) { $uris[] = $this->server->calculateUri($elem->nodeValue); } $xpath = new \DOMXPath($dom); $xpath->registerNameSpace('card', Plugin::NS_CARDDAV); $xpath->registerNameSpace('dav', 'urn:DAV'); $contentType = $xpath->evaluate("string(/card:addressbook-multiget/dav:prop/card:address-data/@content-type)"); $version = $xpath->evaluate("string(/card:addressbook-multiget/dav:prop/card:address-data/@version)"); if ($version) { $contentType .= '; version=' . $version; } $vcardType = $this->negotiateVCard($contentType); $propertyList = []; foreach ($this->server->getPropertiesForMultiplePaths($uris, $properties) as $props) { if (isset($props['200']['{' . self::NS_CARDDAV . '}address-data'])) { $props['200']['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard($props[200]['{' . self::NS_CARDDAV . '}address-data'], $vcardType); } $propertyList[] = $props; } $prefer = $this->server->getHTTPPRefer(); $this->server->httpResponse->setStatus(207); $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer'); $this->server->httpResponse->setBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal'])); }
/** * Unserializes the property. * * This static method should return a an instance of this object. * * @param \DOMElement $prop * @param array $propertyMap * @return DAV\IProperty */ static function unserialize(\DOMElement $prop, array $propertyMap) { $xpath = new \DOMXPath($prop->ownerDocument); $xpath->registerNamespace('d', 'urn:DAV'); // Finding the 'response' element $xResponses = $xpath->evaluate('d:response', $prop); $result = []; for ($jj = 0; $jj < $xResponses->length; $jj++) { $xResponse = $xResponses->item($jj); // Parsing 'href' $href = Href::unserialize($xResponse, $propertyMap); $properties = []; // Parsing 'status' in 'd:response' $responseStatus = $xpath->evaluate('string(d:status)', $xResponse); if ($responseStatus) { list(, $responseStatus, ) = explode(' ', $responseStatus, 3); } // Parsing 'propstat' $xPropstat = $xpath->query('d:propstat', $xResponse); for ($ii = 0; $ii < $xPropstat->length; $ii++) { // Parsing 'status' $status = $xpath->evaluate('string(d:status)', $xPropstat->item($ii)); list(, $statusCode, ) = explode(' ', $status, 3); $usedPropertyMap = $statusCode == '200' ? $propertyMap : []; // Parsing 'prop' $properties[$statusCode] = DAV\XMLUtil::parseProperties($xPropstat->item($ii), $usedPropertyMap); } $result[] = new Response($href->getHref(), $properties, $responseStatus ? $responseStatus : null); } return new self($result); }
/** * This function handles the addressbook-multiget REPORT. * * This report is used by the client to fetch the content of a series * of urls. Effectively avoiding a lot of redundant requests. * * @param \DOMNode $dom * @return void */ public function addressbookMultiGetReport($dom) { $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)); $hrefElems = $dom->getElementsByTagNameNS('urn:DAV', 'href'); $propertyList = array(); foreach ($hrefElems as $elem) { $uri = $this->server->calculateUri($elem->nodeValue); list($propertyList[]) = $this->server->getPropertiesForPath($uri, $properties); } $prefer = $this->server->getHTTPPRefer(); $this->server->httpResponse->sendStatus(207); $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer'); $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal'])); }
/** * Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object * * @param string $body * @return DAV\Locks\LockInfo */ protected function parseLockRequest($body) { $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($body), null, LIBXML_NOWARNING); $xml->registerXPathNamespace('d', 'urn:DAV'); $lockInfo = new LockInfo(); $children = $xml->children("urn:DAV"); $lockInfo->owner = (string) $children->owner; $lockInfo->token = DAV\UUIDUtil::getUUID(); $lockInfo->scope = count($xml->xpath('d:lockscope/d:exclusive')) > 0 ? LockInfo::EXCLUSIVE : LockInfo::SHARED; return $lockInfo; }
/** * Parses a WebDAV multistatus response body * * This method returns an array with the following structure * * [ * 'url/to/resource' => [ * '200' => [ * '{DAV:}property1' => 'value1', * '{DAV:}property2' => 'value2', * ], * '404' => [ * '{DAV:}property1' => null, * '{DAV:}property2' => null, * ], * ], * 'url/to/resource2' => [ * .. etc .. * ] * ] * * * @param string $body xml body * @return array */ function parseMultiStatus($body) { try { $dom = XMLUtil::loadDOMDocument($body); } catch (Exception\BadRequest $e) { throw new \InvalidArgumentException('The body passed to parseMultiStatus could not be parsed. Is it really xml?'); } $responses = Property\ResponseList::unserialize($dom->documentElement, $this->propertyMap); $result = []; foreach ($responses->getResponses() as $response) { $result[$response->getHref()] = $response->getResponseProperties(); } return $result; }
/** * Deserializes a DOM element into a property object. * * @param \DOMElement $dom * @return Principal */ public static function unserialize(\DOMElement $dom) { $parent = $dom->firstChild; while (!DAV\XMLUtil::toClarkNotation($parent)) { $parent = $parent->nextSibling; } switch (DAV\XMLUtil::toClarkNotation($parent)) { case '{DAV:}unauthenticated': return new self(self::UNAUTHENTICATED); case '{DAV:}authenticated': return new self(self::AUTHENTICATED); case '{DAV:}href': return new self(self::HREF, $parent->textContent); case '{DAV:}all': return new self(self::ALL); default: throw new DAV\Exception\BadRequest('Unexpected element (' . DAV\XMLUtil::toClarkNotation($parent) . '). Could not deserialize'); } }
/** * @depends testSupportedReportSetProperty * @depends testCalendarMultiGetReport */ function testCalendarQueryReport1ObjectNoCalData() { $body = '<?xml version="1.0"?>' . '<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">' . '<d:prop>' . ' <d:getetag />' . '</d:prop>' . '<c:filter>' . ' <c:comp-filter name="VCALENDAR">' . ' <c:comp-filter name="VEVENT" />' . ' </c:comp-filter>' . '</c:filter>' . '</c:calendar-query>'; $request = new HTTP\Request(array('REQUEST_METHOD' => 'REPORT', 'REQUEST_URI' => '/calendars/user1/UUID-123467/UUID-2345', 'HTTP_DEPTH' => '0')); $request->setBody($body); $this->server->httpRequest = $request; $this->server->exec(); $this->assertEquals('HTTP/1.1 207 Multi-Status', $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); $xml->registerXPathNamespace('d', 'urn:DAV'); $xml->registerXPathNamespace('c', 'urn:ietf:params:xml:ns:caldav'); $check = array('/d:multistatus', '/d:multistatus/d:response', '/d:multistatus/d:response/d:href', '/d:multistatus/d:response/d:propstat', '/d:multistatus/d:response/d:propstat/d:prop', '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK'); foreach ($check as $v1 => $v2) { $xpath = is_int($v1) ? $v2 : $v1; $result = $xml->xpath($xpath); $this->assertEquals(1, count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body); if (!is_int($v1)) { $this->assertEquals($v2, (string) $result[0]); } } }