Skip to content

Commit e7d5b94

Browse files
authored
Merge pull request #43 from veewee/decoder-libxml-options
Allow configuration of libxml options for decoding XML
2 parents f0cd4b6 + 137557a commit e7d5b94

File tree

6 files changed

+67
-10
lines changed

6 files changed

+67
-10
lines changed

src/Encoder/Method/ResponseEncoder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private function decode(MethodContext $context, string $xml): array
101101
// The SoapResponse only contains the payload of the response (with no headers).
102102
// It can be parsed directly as XML.
103103
invariant($xml !== '', 'Expected a non-empty response payload. Received an empty HTTP response');
104-
$parts = (new OperationReader($meta))($xml)->elements();
104+
$parts = (new OperationReader($meta))($xml, $context->registry->decoderLibXmlOptions())->elements();
105105

106106
return map(
107107
$parts,

src/EncoderRegistry.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ final class EncoderRegistry
2626
/**
2727
* @param MutableMap<string, XmlEncoder<mixed, string>> $simpleTypeMap
2828
* @param MutableMap<string, XmlEncoder<mixed, string>> $complextTypeMap
29+
* @param int $decoderLibXmlOptions - bitmask of LIBXML_* constants https://www.php.net/manual/en/libxml.constants.php
2930
*/
3031
private function __construct(
3132
private MutableMap $simpleTypeMap,
32-
private MutableMap $complextTypeMap
33+
private MutableMap $complextTypeMap,
34+
private int $decoderLibXmlOptions = 0,
3335
) {
3436
}
3537

@@ -341,4 +343,22 @@ public function detectEncoderForContext(Context $context): XmlEncoder
341343
{
342344
return EncoderDetector::default()($context);
343345
}
346+
347+
/**
348+
* @param int $libXmlOptions - bitmask of LIBXML_* constants https://www.php.net/manual/en/libxml.constants.php
349+
*/
350+
public function setDecoderLibXmlOptions(int $libXmlOptions): self
351+
{
352+
$this->decoderLibXmlOptions = $libXmlOptions;
353+
354+
return $this;
355+
}
356+
357+
/**
358+
* @return int - bitmask of LIBXML_* constants https://www.php.net/manual/en/libxml.constants.php
359+
*/
360+
public function decoderLibXmlOptions(): int
361+
{
362+
return $this->decoderLibXmlOptions;
363+
}
344364
}

src/Xml/Reader/OperationReader.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ public function __construct(
2222
* Reads all operation response message parts:
2323
*
2424
* @param non-empty-string $xml
25+
* @param int $libXmlOptions - bitmask of LIBXML_* constants https://www.php.net/manual/en/libxml.constants.php
2526
*/
26-
public function __invoke(string $xml): ElementList
27+
public function __invoke(string $xml, int $libXmlOptions = 0): ElementList
2728
{
2829
$bindingStyle = BindingStyle::tryFrom($this->meta->bindingStyle()->unwrapOr(BindingStyle::DOCUMENT->value));
2930

3031
// The Response can contain out of multiple response parts.
3132
// Therefore, it is being wrapped by a central root element:
32-
$body = (new SoapEnvelopeReader())($xml);
33+
$body = (new SoapEnvelopeReader())($xml, $libXmlOptions);
3334
$bodyElement = $body->element();
3435

3536
$elements = match($bindingStyle) {

src/Xml/Reader/SoapEnvelopeReader.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@
88
use Soap\Xml\Locator\SoapBodyLocator;
99
use VeeWee\Xml\Dom\Document;
1010
use function VeeWee\Xml\Dom\Assert\assert_element;
11+
use function VeeWee\Xml\Dom\Configurator\loader;
12+
use function VeeWee\Xml\Dom\Loader\xml_string_loader;
1113

1214
final class SoapEnvelopeReader
1315
{
1416
/**
1517
* @param non-empty-string $xml
18+
* @param int $libXmlOptions - bitmask of LIBXML_* constants https://www.php.net/manual/en/libxml.constants.php
1619
*/
17-
public function __invoke(string $xml): Element
20+
public function __invoke(string $xml, int $libXmlOptions = 0): Element
1821
{
19-
$envelope = Document::fromXmlString($xml);
22+
$envelope = Document::configure(loader(xml_string_loader($xml, $libXmlOptions)));
2023

2124
// Make sure it does not contain a fault response before parsing the body parts.
2225
(new SoapFaultGuard())($envelope);

tests/Unit/Xml/Reader/OperationReaderTest.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@
1212
use Soap\Engine\Metadata\Model\MethodMeta;
1313
use Soap\WsdlReader\Model\Definitions\BindingStyle;
1414
use function Psl\Vec\map;
15+
use const LIBXML_NOCDATA;
1516

1617
#[CoversClass(OperationReader::class)]
1718
final class OperationReaderTest extends TestCase
1819
{
1920
#[DataProvider('provideEnvelopeCases')]
20-
public function test_it_can_read_a_soap_envelope(MethodMeta $meta, string $envelope, array $expected): void
21+
public function test_it_can_read_a_soap_envelope(MethodMeta $meta, string $envelope, array $expected, int $libXmlOptions = 0): void
2122
{
2223
$reader = new OperationReader($meta);
23-
$actual = $reader($envelope);
24+
$actual = $reader($envelope, $libXmlOptions);
2425

2526
static::assertSame(
2627
$expected,
@@ -91,5 +92,19 @@ public static function provideEnvelopeCases()
9192
'<c>c</c>',
9293
],
9394
];
95+
96+
yield 'xml-options' => [
97+
$methodMeta->withBindingStyle(BindingStyle::DOCUMENT->value),
98+
<<<EOXML
99+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
100+
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
101+
<Request><![CDATA[content]]></Request>
102+
</soap:Body>
103+
</soap:Envelope>
104+
EOXML,
105+
['<Request>content</Request>'],
106+
LIBXML_NOCDATA
107+
];
108+
94109
}
95110
}

tests/Unit/Xml/Reader/SoapEnvelopeReaderTest.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313
use Soap\Encoding\Xml\Reader\SoapEnvelopeReader;
1414
use Soap\Encoding\Xml\Writer\SoapEnvelopeWriter;
1515
use Soap\WsdlReader\Model\Definitions\SoapVersion;
16+
use const LIBXML_NOCDATA;
1617

1718
#[CoversClass(SoapEnvelopeWriter::class)]
1819
#[CoversClass(SoapFaultGuard::class)]
1920
final class SoapEnvelopeReaderTest extends TestCase
2021
{
2122
#[DataProvider('provideEnvelopeCases')]
22-
public function test_it_can_read_a_soap_envelope(SoapVersion $version, string $envelope, string $expected): void
23+
public function test_it_can_read_a_soap_envelope(SoapVersion $version, string $envelope, string $expected, int $libXmlOptions = 0): void
2324
{
2425
$reader = new SoapEnvelopeReader();
25-
$actual = $reader($envelope);
26+
$actual = $reader($envelope, $libXmlOptions);
2627

2728
static::assertXmlStringEqualsXmlString($expected, $actual->value());
2829
}
@@ -83,5 +84,22 @@ public static function provideEnvelopeCases()
8384
</soap:Body>
8485
EOXML,
8586
];
87+
88+
yield 'xml-options' => [
89+
SoapVersion::SOAP_12,
90+
<<<EOXML
91+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/">
92+
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/">
93+
<Request><![CDATA[content]]></Request>
94+
</soap:Body>
95+
</soap:Envelope>
96+
EOXML,
97+
<<<EOXML
98+
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/">
99+
<Request>content</Request>
100+
</soap:Body>
101+
EOXML,
102+
LIBXML_NOCDATA
103+
];
86104
}
87105
}

0 commit comments

Comments
 (0)