为了账号安全,请及时绑定邮箱和手机立即绑定

有没有更简洁的方法来实现 NHS 数据从 XML 到 JSON 的转换

有没有更简洁的方法来实现 NHS 数据从 XML 到 JSON 的转换

PHP
慕尼黑5688855 2021-12-03 14:35:10
我正在使用来自公共 NHS API 的位置和地址数据,它以 XML 格式输入,我已将其转换为 JSON 以在我的 web 应用程序中使用。我的代码正在运行并产生所需的结果,但是我不禁对这段代码中嵌套的 foreach 循环的数量感到畏缩。有没有更干净的方法来实现相同的结果,并且性能更高?我曾尝试使用 simplexml_load_string 和许多变体,但它拒绝输出/解析包含 s:organisationSummary 数据的嵌套元素的内容。这是 PHP 类class XmlElement {    public $name;    public $attributes;    public $content;    public $children;}class GpService{    protected $apiKey;    public function __construct()    {        $this->apiKey = env('NHS_API_KEY');    }    public function xmlToObject($xml) {        $parser = xml_parser_create();        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);        xml_parse_into_struct($parser, $xml, $tags);        xml_parser_free($parser);        $elements = array();  // the currently filling [child] XmlElement array        $stack = array();        foreach ($tags as $tag) {          $index = count($elements);          if ($tag['type'] == "complete" || $tag['type'] == "open") {            $elements[$index] = new XmlElement;            $elements[$index]->name = $tag['tag'];            $elements[$index]->attributes = (isset($tag['attributes']))?$tag['attributes']:null;            $elements[$index]->content = (isset($tag['value']))?$tag['value']:null;            if ($tag['type'] == "open") {  // push              $elements[$index]->children = array();              $stack[count($stack)] = &$elements;              $elements = &$elements[$index]->children;            }          }          if ($tag['type'] == "close") {  // pop            $elements = &$stack[count($stack) - 1];            unset($stack[count($stack) - 1]);          }        }        return $elements[0];  // the single top-level element    }    }}
查看完整描述

2 回答

?
繁花不似锦

TA贡献1851条经验 获得超4个赞

您可以使用 DOM 和 XPath 表达式。所有数据都在{https://api.nhs.uk/data/services}organisationSummary节点内。


下面的示例注册service命名空间的前缀https://api.nhs.uk/data/services(这就是s示例中的 解析为)。然后它{https://api.nhs.uk/data/services}organisationSummary使用//service:organisationSummary表达式获取任何节点。


对于每个组织,它$item使用标量值的表达式构建一个变量。循环用于{https://api.nhs.uk/data/services}addressLine节点。


// create the DOM document and load the XML 

$document = new DOMDocument();

$document->loadXML($xml);

// create an Xpath instance for the document - register namespace

$xpath = new DOMXpath($document);

$xpath->registerNamespace('service', 'https://api.nhs.uk/data/services');

$json = [

  "success" => true,

  // force object for data - it will be an array otherwise

  "data" => new stdClass()

];


// iterate over all organisationSummary nodes

foreach ($xpath->evaluate('//service:organisationSummary') as $index => $organisation) {

  // fetch single values

  $item = [

    "name" => $xpath->evaluate('string(service:name)', $organisation),

    "odscode" => $xpath->evaluate('string(service:odsCode)', $organisation),

    "postcode" => $xpath->evaluate('string(service:address/service:postcode)', $organisation),

    "telephone" => $xpath->evaluate('string(service:contact/service:telephone)', $organisation),

    "longitude" => $xpath->evaluate('string(service:geographicCoordinates/service:longitude)', $organisation),

    "latitude" => $xpath->evaluate('string(service:geographicCoordinates/service:latitude)', $organisation),

    "distance" => $xpath->evaluate('string(service:Distance)', $organisation)

  ];

  // add the addressLine values

  foreach ($xpath->evaluate('service:address/service:addressLine', $organisation) as $lineIndex => $line) {

    $item['addressline'.$lineIndex] = $line->textContent;

  }

  // add the $item

  $json['data']->{$index} = $item;

}


echo json_encode($json, JSON_PRETTY_PRINT);

输出:


{

    "success": true,

    "data": {

        "0": {

            "name": "Highfields Surgery (R Wadhwa)",

            "odscode": "C82116",

            "postcode": "LE2 0NN",

            "telephone": "01162543253",

            "longitude": "-1.11859357357025",

            "latitude": "52.6293983459473",

            "distance": "0.247038430918239",

            "addressline0": "25 Severn Street",

            "addressline1": "Leicester",

            "addressline2": "Leicestershire"

        },

        "1": {

            "name": "Dr R Kapur & Partners",

            "odscode": "C82659",

            "postcode": "LE2 0TA",

            "telephone": "01162951258",

            "longitude": "-1.11907768249512",

            "latitude": "52.6310386657715",

            "distance": "0.30219913005026",

            "addressline0": "St Peters Health Centre",

            "addressline1": "Sparkenhoe Street",

            "addressline2": "Leicester",

            "addressline3": "Leicestershire"

        },

        ...


查看完整回答
反对 回复 2021-12-03
?
冉冉说

TA贡献1877条经验 获得超1个赞

您需要使用适当的方法来遍历 XML 文档,而不是查看每个元素并检查其名称。


您的两个最佳选择是 DOM 方法和 XPath。如果您使用过前端 JavaScript 代码(例如document.getElementsByTagName或document.getElementById),您就会熟悉前者。后者具有更陡峭的学习曲线,但功能要强大得多。(XSLT 也是转换 XML 的好选择,但我对它不是很熟悉。)


不过,第一步是使用正确的 XML 库。您使用的 XML 函数级别非常低。我建议改用 PHP 的DomDocument扩展。让我们潜入吧!


<?php

$xml = file_get_contents("nhs.xml");

// assume XML document is stored in a variable called $xml

$dom = new DomDocument;

$dom->loadXml($xml);

// thankfully we can ignore namespaces!

$summaries = $dom->getElementsByTagName("organisationSummary");

// go through each <organisationSummary> element

foreach ($summaries as $os) {

    $entry_data = [

        // note we're using $os and not $dom now, so we get child elements of this particular element

        "name"         => $os->getElementsByTagName("name")[0]->textContent,

        "odscode"      => $os->getElementsByTagName("odsCode")[0]->textContent,

        "addressline0" => $os->getElementsByTagName("addressLine")[0]->textContent,

        // provide a default empty string in case there's no further lines

        "addressline1" => $os->getElementsByTagName("addressLine")[1]->textContent ?? "",

        "addressline2" => $os->getElementsByTagName("addressLine")[2]->textContent ?? "",

        "addressline3" => $os->getElementsByTagName("addressLine")[3]->textContent ?? "",

        "postcode"     => $os->getElementsByTagName("postcode")[0]->textContent,

        "telephone"    => $os->getElementsByTagName("telephone")[0]->textContent,

        "longitude"    => $os->getElementsByTagName("longitude")[0]->textContent,

        "latitude"     => $os->getElementsByTagName("latitude")[0]->textContent,

        "distance"     => $os->getElementsByTagName("Distance")[0]->textContent,

    ];

    $json_data[] = $entry_data;

}

if (count($json_data)) {

    $output = ["success" => true, "data" => $json_data];

} else {

    $output = ["success" => false];

}

echo json_encode($output, JSON_PRETTY_PRINT);


查看完整回答
反对 回复 2021-12-03
  • 2 回答
  • 0 关注
  • 166 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信