diff --git a/src/BeSimple/SoapClient/WsdlDownloader.php b/src/BeSimple/SoapClient/WsdlDownloader.php
index e3a5d0b..1c1d413 100644
--- a/src/BeSimple/SoapClient/WsdlDownloader.php
+++ b/src/BeSimple/SoapClient/WsdlDownloader.php
@@ -13,6 +13,8 @@
namespace BeSimple\SoapClient;
use BeSimple\SoapClient\Curl\Curl;
+use BeSimple\SoapClient\Xml\RemoteFileResolver;
+use BeSimple\SoapClient\Xml\XmlFileDomDocumentProcessor;
use BeSimple\SoapCommon\Cache;
use BeSimple\SoapCommon\Helper;
use DOMDocument;
@@ -30,6 +32,11 @@ use Exception;
*/
class WsdlDownloader
{
+ public static function instantiateDownloader()
+ {
+ return new self();
+ }
+
/**
* @param Curl $curl
* @param string $wsdlPath WSDL file URL/path
@@ -39,10 +46,10 @@ class WsdlDownloader
*/
public function getWsdlPath(Curl $curl, $wsdlPath, $wsdCacheType, $resolveRemoteIncludes = true)
{
- $isRemoteFile = $this->isRemoteFile($wsdlPath);
+ $isRemoteFile = RemoteFileResolver::instantiateResolver()->isRemoteFile($wsdlPath);
$isCacheEnabled = $wsdCacheType === Cache::TYPE_NONE ? false : Cache::isEnabled();
if ($isCacheEnabled === true) {
- $cacheFilePath = Cache::getDirectory().DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdlPath).'.cache';
+ $cacheFilePath = Cache::getDirectory() . DIRECTORY_SEPARATOR . 'wsdl_' . md5($wsdlPath) . '.cache';
$isCacheExisting = file_exists($cacheFilePath);
if ($isCacheExisting) {
$fileModificationTime = filemtime($cacheFilePath);
@@ -54,46 +61,17 @@ class WsdlDownloader
$isCacheExisting = $isCacheValid = false;
}
if ($isCacheExisting === false || $isCacheValid === false) {
- $this->writeCacheFile($curl, $wsdCacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile);
+ XmlFileDomDocumentProcessor::writeCacheFile($curl, $wsdCacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile);
}
return $this->getLocalWsdlPath($cacheFilePath);
- } else {
-
- if ($isRemoteFile === true) {
- return $wsdlPath;
- }
-
- return $this->getLocalWsdlPath($wsdlPath);
}
- }
-
- private function writeCacheFile(Curl $curl, $cacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile)
- {
if ($isRemoteFile === true) {
- $curlResponse = $curl->executeCurlWithCachedSession($wsdlPath);
- if ($curlResponse->curlStatusSuccess()) {
- if (mb_strlen($curlResponse->getResponseBody()) === 0) {
- throw new Exception('Could not write WSDL cache file: empty curl response from: '.$wsdlPath);
- }
- if ($resolveRemoteIncludes === true) {
- $document = $this->getXmlFileDomDocument($curl, $cacheType, $curlResponse->getResponseBody(), $wsdlPath);
- $this->saveXmlDomDocument($document, $cacheFilePath);
- } else {
- file_put_contents($cacheFilePath, $curlResponse->getResponseBody());
- }
- } else {
- throw new Exception('Could not write WSDL cache file: Download failed with message: '.$curlResponse->getCurlErrorMessage());
- }
- } else {
- if (file_exists($wsdlPath)) {
- $document = $this->getXmlFileDomDocument($curl, $cacheType, file_get_contents($wsdlPath));
- $this->saveXmlDomDocument($document, $cacheFilePath);
- } else {
- throw new Exception('Could write WSDL cache file: local file does not exist: '.$wsdlPath);
- }
+ return $wsdlPath;
}
+
+ return $this->getLocalWsdlPath($wsdlPath);
}
private function getLocalWsdlPath($wsdlPath)
@@ -104,164 +82,6 @@ class WsdlDownloader
}
- throw new Exception('Could not download WSDL: local file does not exist: '.$wsdlPath);
- }
-
- /**
- * @param string $wsdlPath File URL/path
- * @return boolean
- */
- private function isRemoteFile($wsdlPath)
- {
- $parsedUrlOrFalse = @parse_url($wsdlPath);
- if ($parsedUrlOrFalse !== false) {
- if (isset($parsedUrlOrFalse['scheme']) && substr($parsedUrlOrFalse['scheme'], 0, 4) === 'http') {
-
- return true;
- }
-
- return false;
- }
-
- throw new Exception('Could not determine wsdlPath is remote: '.$wsdlPath);
- }
-
- /**
- * Resolves remote WSDL/XSD includes within the WSDL files.
- *
- * @param Curl $curl
- * @param int $cacheType
- * @param string $xmlFileSource XML file contents
- * @param boolean $parentFilePath Parent file name
- * @return DOMDocument
- */
- private function getXmlFileDomDocument(Curl $curl, $cacheType, $xmlFileSource, $parentFilePath = null)
- {
- $document = new DOMDocument('1.0', 'utf-8');
- if ($document->loadXML($xmlFileSource) === false) {
- throw new Exception('Could not save downloaded WSDL cache: '.$xmlFileSource);
- }
-
- $xpath = new DOMXPath($document);
- $this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_WSDL, Helper::NS_WSDL, 'location', $parentFilePath);
- $this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA, 'schemaLocation', $parentFilePath);
-
- return $document;
- }
-
- private function saveXmlDomDocument(DOMDocument $document, $cacheFilePath)
- {
- try {
- $xmlContents = $document->saveXML();
- if ($xmlContents === '') {
- throw new Exception('Could not write WSDL cache file: DOMDocument returned empty XML file');
- }
- file_put_contents($cacheFilePath, $xmlContents);
- } catch (Exception $e) {
- unlink($cacheFilePath);
- throw new Exception('Could not write WSDL cache file: save method returned error: ' . $e->getMessage());
- }
- }
-
- private function updateXmlDocument(
- Curl $curl,
- $cacheType,
- DOMXPath $xpath,
- $schemaPrefix,
- $schemaUrl,
- $locationAttributeName,
- $parentFilePath = null
- ) {
- $xpath->registerNamespace($schemaPrefix, $schemaUrl);
- $nodes = $xpath->query('.//'.$schemaPrefix.':include | .//'.$schemaPrefix.':import');
- if ($nodes->length > 0) {
- foreach ($nodes as $node) {
- /** @var DOMElement $node */
- $locationPath = $node->getAttribute($locationAttributeName);
- if ($locationPath !== '') {
- if ($this->isRemoteFile($locationPath)) {
- $node->setAttribute(
- $locationAttributeName,
- $this->getWsdlPath(
- $curl,
- $locationPath,
- $cacheType,
- true
- )
- );
- } elseif ($parentFilePath !== null) {
- $node->setAttribute(
- $locationAttributeName,
- $this->getWsdlPath(
- $curl,
- $this->resolveRelativePathInUrl($parentFilePath, $locationPath),
- $cacheType,
- true
- )
- );
- }
- }
- }
- }
- }
-
- /**
- * Resolves the relative path to base into an absolute.
- *
- * @param string $base Base path
- * @param string $relative Relative path
- *
- * @return string
- */
- private function resolveRelativePathInUrl($base, $relative)
- {
- $urlParts = parse_url($base);
-
- // combine base path with relative path
- if (isset($urlParts['path']) && mb_strlen($relative) > 0 && '/' === $relative{0}) {
- // $relative is absolute path from domain (starts with /)
- $path = $relative;
- } elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']) )) {
- // base path is directory
- $path = $urlParts['path'].$relative;
- } elseif (isset($urlParts['path'])) {
- // strip filename from base path
- $path = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')).'/'.$relative;
- } else {
- // no base path
- $path = '/'.$relative;
- }
-
- // foo/./bar ==> foo/bar
- // remove double slashes
- $path = preg_replace(array('#/\./#', '#/+#'), '/', $path);
-
- // split path by '/'
- $parts = explode('/', $path);
-
- // resolve /../
- foreach ($parts as $key => $part) {
- if ($part === '..') {
- $keyToDelete = $key - 1;
- while ($keyToDelete > 0) {
- if (isset($parts[$keyToDelete])) {
- unset($parts[$keyToDelete]);
-
- break;
- }
-
- $keyToDelete--;
- }
-
- unset($parts[$key]);
- }
- }
-
- $hostname = $urlParts['scheme'].'://'.$urlParts['host'];
- if (isset($urlParts['port'])) {
- $hostname .= ':'.$urlParts['port'];
- }
-
- return $hostname.implode('/', $parts);
+ throw new Exception('Could not download WSDL: local file does not exist: ' . $wsdlPath);
}
}
diff --git a/src/BeSimple/SoapClient/Xml/Path/RelativePathResolver.php b/src/BeSimple/SoapClient/Xml/Path/RelativePathResolver.php
new file mode 100644
index 0000000..2417478
--- /dev/null
+++ b/src/BeSimple/SoapClient/Xml/Path/RelativePathResolver.php
@@ -0,0 +1,75 @@
+ 0 && $isRelativePathAbsolute) {
+ // $relative is absolute path from domain (starts with /)
+ $path = $relative;
+ } elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']) )) {
+ // base path is directory
+ $path = $urlParts['path'].$relative;
+ } elseif (isset($urlParts['path'])) {
+ // strip filename from base path
+ $path = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')).'/'.$relative;
+ } else {
+ // no base path
+ $path = '/'.$relative;
+ }
+
+ // foo/./bar ==> foo/bar
+ // remove double slashes
+ $path = preg_replace(array('#/\./#', '#/+#'), '/', $path);
+
+ // split path by '/'
+ $parts = explode('/', $path);
+
+ // resolve /../
+ foreach ($parts as $key => $part) {
+ if ($part === '..') {
+ $keyToDelete = $key - 1;
+ while ($keyToDelete > 0) {
+ if (isset($parts[$keyToDelete])) {
+ unset($parts[$keyToDelete]);
+
+ break;
+ }
+
+ $keyToDelete--;
+ }
+
+ unset($parts[$key]);
+ }
+ }
+
+ $hostname = $urlParts['scheme'].'://'.$urlParts['host'];
+ if (isset($urlParts['port'])) {
+ $hostname .= ':'.$urlParts['port'];
+ }
+ $implodedParts = implode('/', $parts);
+ if (substr($implodedParts, 0, 1) !== '/') {
+ $implodedParts = '/'.$implodedParts;
+ }
+
+ return $hostname.$implodedParts;
+ }
+}
diff --git a/src/BeSimple/SoapClient/Xml/RemoteFileResolver.php b/src/BeSimple/SoapClient/Xml/RemoteFileResolver.php
new file mode 100644
index 0000000..0f6d0e7
--- /dev/null
+++ b/src/BeSimple/SoapClient/Xml/RemoteFileResolver.php
@@ -0,0 +1,32 @@
+registerNamespace($schemaPrefix, $schemaUrl);
+ $nodes = $xpath->query('.//'.$schemaPrefix.':include | .//'.$schemaPrefix.':import');
+ if ($nodes->length > 0) {
+ foreach ($nodes as $node) {
+ /** @var DOMElement $node */
+ $locationPath = $node->getAttribute($locationAttributeName);
+ if ($locationPath !== '') {
+ if (RemoteFileResolver::instantiateResolver()->isRemoteFile($locationPath)) {
+ $node->setAttribute(
+ $locationAttributeName,
+ WsdlDownloader::instantiateDownloader()->getWsdlPath(
+ $curl,
+ $locationPath,
+ $cacheType,
+ true
+ )
+ );
+ } elseif ($parentFilePath !== null) {
+ $node->setAttribute(
+ $locationAttributeName,
+ WsdlDownloader::instantiateDownloader()->getWsdlPath(
+ $curl,
+ self::resolveRelativePathInUrl($parentFilePath, $locationPath),
+ $cacheType,
+ true
+ )
+ );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Resolves the relative path to base into an absolute.
+ *
+ * @param string $base Base path
+ * @param string $relative Relative path
+ *
+ * @return string
+ */
+ private static function resolveRelativePathInUrl($base, $relative)
+ {
+ $urlParts = parse_url($base);
+ $isRelativePathAbsolute = 0 === strpos($relative, '/') || 0 === strpos($relative, '..');
+
+ // combine base path with relative path
+ if (isset($urlParts['path']) && mb_strlen($relative) > 0 && $isRelativePathAbsolute) {
+ // $relative is absolute path from domain (starts with /)
+ $path = $relative;
+ } elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']) )) {
+ // base path is directory
+ $path = $urlParts['path'].$relative;
+ } elseif (isset($urlParts['path'])) {
+ // strip filename from base path
+ $path = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')).'/'.$relative;
+ } else {
+ // no base path
+ $path = '/'.$relative;
+ }
+
+ // foo/./bar ==> foo/bar
+ // remove double slashes
+ $path = preg_replace(array('#/\./#', '#/+#'), '/', $path);
+
+ // split path by '/'
+ $parts = explode('/', $path);
+
+ // resolve /../
+ foreach ($parts as $key => $part) {
+ if ($part === '..') {
+ $keyToDelete = $key - 1;
+ while ($keyToDelete > 0) {
+ if (isset($parts[$keyToDelete])) {
+ unset($parts[$keyToDelete]);
+
+ break;
+ }
+
+ $keyToDelete--;
+ }
+
+ unset($parts[$key]);
+ }
+ }
+
+ $hostname = $urlParts['scheme'].'://'.$urlParts['host'];
+ if (isset($urlParts['port'])) {
+ $hostname .= ':'.$urlParts['port'];
+ }
+ if (substr($hostname, -1) !== '/') {
+ $hostname .= '/';
+ }
+
+ return $hostname.implode('/', $parts);
+ }
+}
diff --git a/src/BeSimple/SoapClient/Xml/XmlFileDomDocumentProcessor.php b/src/BeSimple/SoapClient/Xml/XmlFileDomDocumentProcessor.php
new file mode 100644
index 0000000..1e8f079
--- /dev/null
+++ b/src/BeSimple/SoapClient/Xml/XmlFileDomDocumentProcessor.php
@@ -0,0 +1,77 @@
+executeCurlWithCachedSession($wsdlPath);
+ if ($curlResponse->curlStatusSuccess()) {
+ if (mb_strlen($curlResponse->getResponseBody()) === 0) {
+ throw new Exception('Could not write WSDL cache file: empty curl response from: '.$wsdlPath);
+ }
+ if ($resolveRemoteIncludes === true) {
+ $document = self::getXmlFileDomDocument($curl, $cacheType, $curlResponse->getResponseBody(), $wsdlPath);
+ self::saveXmlDomDocument($document, $cacheFilePath);
+ } else {
+ file_put_contents($cacheFilePath, $curlResponse->getResponseBody());
+ }
+ } else {
+ throw new Exception('Could not write WSDL cache file: Download failed with message: '.$curlResponse->getCurlErrorMessage());
+ }
+ } else {
+ if (file_exists($wsdlPath)) {
+ $document = self::getXmlFileDomDocument($curl, $cacheType, file_get_contents($wsdlPath));
+ self::saveXmlDomDocument($document, $cacheFilePath);
+ } else {
+ throw new Exception('Could write WSDL cache file: local file does not exist: '.$wsdlPath);
+ }
+ }
+ }
+
+ /**
+ * Resolves remote WSDL/XSD includes within the WSDL files.
+ *
+ * @param Curl $curl
+ * @param int $cacheType
+ * @param string $xmlFileSource XML file contents
+ * @param boolean $parentFilePath Parent file name
+ * @return DOMDocument
+ */
+ private static function getXmlFileDomDocument(Curl $curl, $cacheType, $xmlFileSource, $parentFilePath = null)
+ {
+ $document = new DOMDocument('1.0', 'utf-8');
+ if ($document->loadXML($xmlFileSource) === false) {
+ throw new Exception('Could not save downloaded WSDL cache: '.$xmlFileSource);
+ }
+
+ $xpath = new DOMXPath($document);
+ $xmlDomDocumentImportReplacer = XmlDomDocumentImportReplacer::instantiateReplacer();
+ $xmlDomDocumentImportReplacer->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_WSDL, Helper::NS_WSDL, 'location', $parentFilePath);
+ $xmlDomDocumentImportReplacer->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA, 'schemaLocation', $parentFilePath);
+
+ return $document;
+ }
+
+ private static function saveXmlDomDocument(DOMDocument $document, $cacheFilePath)
+ {
+ try {
+ $xmlContents = $document->saveXML();
+ if ($xmlContents === '') {
+ throw new Exception('Could not write WSDL cache file: DOMDocument returned empty XML file');
+ }
+ file_put_contents($cacheFilePath, $xmlContents);
+ } catch (Exception $e) {
+ unlink($cacheFilePath);
+ throw new Exception('Could not write WSDL cache file: save method returned error: ' . $e->getMessage());
+ }
+ }
+}
diff --git a/tests/BeSimple/SoapClient/Xml/Path/RelativePathResolverTest.php b/tests/BeSimple/SoapClient/Xml/Path/RelativePathResolverTest.php
new file mode 100644
index 0000000..728554e
--- /dev/null
+++ b/tests/BeSimple/SoapClient/Xml/Path/RelativePathResolverTest.php
@@ -0,0 +1,65 @@
+relativePathResolver = new RelativePathResolver();
+ }
+
+ /**
+ * @param string $base
+ * @param string $relative
+ * @param string $assertPath
+ * @dataProvider providePathInfo
+ */
+ public function testResolveRelativePathInUrl($base, $relative, $assertPath)
+ {
+ $path = $this->relativePathResolver->resolveRelativePathInUrl($base, $relative);
+
+ self::assertEquals($assertPath, $path);
+ }
+
+ public function providePathInfo()
+ {
+ return [
+ [
+ 'http://endpoint-location.ltd/',
+ 'Document1.xsd',
+ 'http://endpoint-location.ltd/Document1.xsd',
+ ],
+ [
+ 'http://endpoint-location.ltd:8080/endpoint/',
+ '../Schemas/Common/Document2.xsd',
+ 'http://endpoint-location.ltd:8080/Schemas/Common/Document2.xsd',
+ ],
+ [
+ 'http://endpoint-location.ltd/',
+ '../Schemas/Common/Document3.xsd',
+ 'http://endpoint-location.ltd/Schemas/Common/Document3.xsd',
+ ],
+ [
+ 'http://endpoint-location.ltd/',
+ '/Document4.xsd',
+ 'http://endpoint-location.ltd/Document4.xsd',
+ ],
+ [
+ 'http://endpoint-location.ltd',
+ '/Document5.xsd',
+ 'http://endpoint-location.ltd/Document5.xsd',
+ ],
+ [
+ 'http://endpoint-location.ltd',
+ 'Document6.xsd',
+ 'http://endpoint-location.ltd/Document6.xsd',
+ ]
+ ];
+ }
+}
diff --git a/tests/BeSimple/SoapClient/Xml/RemoteFileResolverTest.php b/tests/BeSimple/SoapClient/Xml/RemoteFileResolverTest.php
new file mode 100644
index 0000000..9e80a14
--- /dev/null
+++ b/tests/BeSimple/SoapClient/Xml/RemoteFileResolverTest.php
@@ -0,0 +1,42 @@
+remoteFileResolver = new RemoteFileResolver();
+ }
+
+ /**
+ * @param string $wsdlPath
+ * @param bool $assertIsRemoteFile
+ * @dataProvider provideWsdlPaths
+ */
+ public function testIsRemoteFile($wsdlPath, $assertIsRemoteFile)
+ {
+ $isRemoteFile = $this->remoteFileResolver->isRemoteFile($wsdlPath);
+
+ self::assertEquals($assertIsRemoteFile, $isRemoteFile);
+ }
+
+ public function provideWsdlPaths()
+ {
+ return [
+ ['http://endpoint.tld/path/to/wsdl.wsdl', self::FILE_IS_REMOTE],
+ ['http://endpoint.tld:1944/path/to/wsdl.wsdl', self::FILE_IS_REMOTE],
+ ['path/to/wsdl.wsdl', self::FILE_IS_NOT_REMOTE],
+ ['../../path/to/wsdl.wsdl', self::FILE_IS_NOT_REMOTE],
+ ['/path/to/wsdl.wsdl', self::FILE_IS_NOT_REMOTE],
+ ];
+ }
+}
diff --git a/tests/BeSimple/SoapClient/Xml/XmlDomDocumentImportReplacerTest.php b/tests/BeSimple/SoapClient/Xml/XmlDomDocumentImportReplacerTest.php
new file mode 100644
index 0000000..0f2c4b9
--- /dev/null
+++ b/tests/BeSimple/SoapClient/Xml/XmlDomDocumentImportReplacerTest.php
@@ -0,0 +1,105 @@
+xmlDomDocumentImportReplacer = new XmlDomDocumentImportReplacer();
+ }
+
+ /**
+ * @param string $xmlSource
+ * @param Curl $curl
+ * @param string $schemaPrefix
+ * @param string $schemaUrl
+ * @param string $locationAttributeName
+ * @param string|null $parentFilePath
+ * @param string|null $assertImportXmlSource
+ * @dataProvider provideXmlDocumentData
+ */
+ public function testUpdateXmlDocument(
+ $xmlSource,
+ Curl $curl,
+ $schemaPrefix,
+ $schemaUrl,
+ $locationAttributeName,
+ $parentFilePath = null,
+ $assertImportXmlSource = null
+ ) {
+ $wsdl = new DOMDocument();
+ $wsdl->loadXML($xmlSource);
+
+ $this->xmlDomDocumentImportReplacer->updateXmlDocument(
+ $curl,
+ Cache::TYPE_NONE,
+ new DOMXPath($wsdl),
+ $schemaPrefix,
+ $schemaUrl,
+ $locationAttributeName,
+ $parentFilePath
+ );
+ $wsdlSource = $wsdl->saveHTML();
+
+ self::assertContains(
+ $assertImportXmlSource,
+ $wsdlSource
+ );
+ }
+
+ public function provideXmlDocumentData()
+ {
+ return [
+ 'wsdlWithoutParentPath' => [
+ file_get_contents(__DIR__.'/testUpdateXmlDocument.wsdl'),
+ new Curl(CurlOptionsBuilder::buildDefault()),
+ Helper::PFX_WSDL,
+ Helper::NS_WSDL,
+ 'location',
+ self::NO_PARENT_FILE_PATH,
+ ''
+ ],
+ 'schemaWithoutParentPath' => [
+ file_get_contents(__DIR__.'/testUpdateXmlDocument.wsdl'),
+ new Curl(CurlOptionsBuilder::buildDefault()),
+ Helper::PFX_XML_SCHEMA,
+ Helper::NS_XML_SCHEMA,
+ 'schemaLocation',
+ self::NO_PARENT_FILE_PATH,
+ ''
+ ],
+ 'wsdlWithParentPath' => [
+ file_get_contents(__DIR__.'/testUpdateXmlDocument.wsdl'),
+ new Curl(CurlOptionsBuilder::buildDefault()),
+ Helper::PFX_WSDL,
+ Helper::NS_WSDL,
+ 'location',
+ 'http://endpoint-location.ltd:8080/endpoint/',
+ ''
+ ],
+ 'schemaWithParentPath' => [
+ file_get_contents(__DIR__.'/testUpdateXmlDocument.wsdl'),
+ new Curl(CurlOptionsBuilder::buildDefault()),
+ Helper::PFX_XML_SCHEMA,
+ Helper::NS_XML_SCHEMA,
+ 'schemaLocation',
+ 'http://endpoint-location.ltd:8080/endpoint/',
+ ''
+ ],
+ ];
+ }
+}
diff --git a/tests/BeSimple/SoapClient/Xml/testUpdateXmlDocument.wsdl b/tests/BeSimple/SoapClient/Xml/testUpdateXmlDocument.wsdl
new file mode 100644
index 0000000..209f0ca
--- /dev/null
+++ b/tests/BeSimple/SoapClient/Xml/testUpdateXmlDocument.wsdl
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TEST-OPERATION-1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file