PHP แปลง XML เป็น JSON


158

ฉันพยายามแปลง xml เป็น json ใน php ถ้าฉันใช้โปรแกรมแปลงอย่างง่ายโดยใช้ xml แบบง่ายและ json_encode ไม่มีคุณสมบัติใด ๆ ในการแสดง xml

$xml = simplexml_load_file("states.xml");
echo json_encode($xml);

ดังนั้นฉันจึงพยายามวิเคราะห์แบบนี้ด้วยตนเอง

foreach($xml->children() as $state)
{
    $states[]= array('state' => $state->name); 
}       
echo json_encode($states);

และเอาท์พุทสำหรับรัฐ{"state":{"0":"Alabama"}}มากกว่า{"state":"Alabama"}

ผมทำอะไรผิดหรือเปล่า?

XML:

<?xml version="1.0" ?>
<states>
    <state id="AL">     
    <name>Alabama</name>
    </state>
    <state id="AK">
        <name>Alaska</name>
    </state>
</states>

เอาท์พุท:

[{"state":{"0":"Alabama"}},{"state":{"0":"Alaska"}

var dump:

object(SimpleXMLElement)#1 (1) {
["state"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#3 (2) {
  ["@attributes"]=>
  array(1) {
    ["id"]=>
    string(2) "AL"
  }
  ["name"]=>
  string(7) "Alabama"
}
[1]=>
object(SimpleXMLElement)#2 (2) {
  ["@attributes"]=>
  array(1) {
    ["id"]=>
    string(2) "AK"
  }
  ["name"]=>
  string(6) "Alaska"
}
}
}

โปรดใส่ตัวอย่างของ XML และโครงสร้างอาร์เรย์สุดท้ายที่คุณมีหลังจากแยกวิเคราะห์ ( var_dumpทำงานได้ดี)
nikc.org

เพิ่มอินพุตเอาต์พุตและ var_dump
Bryan Hadlock

บางโปรแกรมต้อง"Perfec XML เพื่อ JSON แผนที่"ที่เป็นjsonMLดูวิธีการแก้ปัญหาที่นี่
Peter Krauss

คำตอบ:


472

Json & Array จาก XML ใน 3 บรรทัด:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

58
วิธีนี้ไม่ไร้ที่ติ มันทิ้งคุณสมบัติ XML อย่างสมบูรณ์ ดังนั้นถูกตีความว่าเป็น<person my-attribute='name'>John</person> <person>John</person>
Jake Wilson

13
$ xml = simplexml_load_string ($ xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); เพื่อทำให้องค์ประกอบ cdata เรียบ
txyoji

28
@ JakeWilson อาจเป็นเวลา 2 ปีที่ผ่านมาและการแก้ไขเวอร์ชันต่างๆ แต่ใน PHP 5.6.30 วิธีนี้สร้างข้อมูลทั้งหมด คุณสมบัติจะถูกเก็บไว้ในอาร์เรย์ภายใต้@attributesคีย์ดังนั้นจึงทำงานได้อย่างไม่มีที่ติและสวยงาม โค้ดสั้น ๆ 3 บรรทัดช่วยแก้ปัญหาของฉันได้อย่างสวยงาม
AlexanderMP

1
วิธีนี้ใช้ไม่ได้หากคุณมีเนมสเปซหลายรายการคุณสามารถเลือกได้เพียงอันเดียวเท่านั้นซึ่งจะผ่านไปยัง $ json_string: '(
jirislav

1
เก็บไว้ในใจว่าด้วยการแก้ปัญหานี้เมื่ออาจจะมีหลายโหนดที่มีชื่อเดียวกันหนึ่งโหนดจะส่งผลสำคัญเพียงแค่ชี้ไปที่องค์ประกอบ แต่หลายโหนดจะมีผลในการชี้กุญแจสำคัญในการอาร์เรย์ขององค์ประกอบ: -><list><item><a>123</a><a>456</a></item><item><a>123</a></item></list> {"item":[{"a":["123","456"]},{"a":"123"}]}ทางออกที่ php.net โดย ratfactorแก้ปัญหานั้นโดยเก็บองค์ประกอบไว้ในอาร์เรย์เสมอ
Klesun

37

ขออภัยที่ตอบโพสต์เก่า แต่บทความนี้สรุปแนวทางที่ค่อนข้างสั้นกระชับและง่ายต่อการบำรุงรักษา ฉันทดสอบด้วยตัวเองและใช้งานได้ดี

http://lostechies.com/seanbiefeld/2011/10/21/simple-xml-to-json-with-php/

<?php   
class XmlToJson {
    public function Parse ($url) {
        $fileContents= file_get_contents($url);
        $fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
        $fileContents = trim(str_replace('"', "'", $fileContents));
        $simpleXml = simplexml_load_string($fileContents);
        $json = json_encode($simpleXml);

        return $json;
    }
}
?>

4
สิ่งนี้จะไม่ทำงานหากคุณมีแท็กเดียวกันหลายอินสแตนซ์ใน XML ของคุณ json_encode จะลงเอยด้วยการซีเรียลอินสแตนซ์สุดท้ายของแท็กเท่านั้น
ethree

35

ฉันคิดออก json_encode จัดการกับวัตถุที่แตกต่างจากสตริง ฉันโยนวัตถุเป็นสตริงและใช้งานได้ในขณะนี้

foreach($xml->children() as $state)
{
    $states[]= array('state' => (string)$state->name); 
}       
echo json_encode($states);

19

ฉันคิดว่าฉันมาช้าไปงานปาร์ตี้ แต่ฉันได้เขียนฟังก์ชั่นเล็ก ๆ เพื่อให้งานนี้สำเร็จ นอกจากนี้ยังดูแลแอ็ตทริบิวต์เนื้อหาข้อความและแม้ว่าหลายโหนดที่มีชื่อโหนดเดียวกันจะเป็นพี่น้องกัน

การปฏิเสธความรับผิดชอบ: ฉันไม่ใช่คนพื้นเมืองของ PHP ดังนั้นโปรดอดทนกับข้อผิดพลาดง่าย ๆ

function xml2js($xmlnode) {
    $root = (func_num_args() > 1 ? false : true);
    $jsnode = array();

    if (!$root) {
        if (count($xmlnode->attributes()) > 0){
            $jsnode["$"] = array();
            foreach($xmlnode->attributes() as $key => $value)
                $jsnode["$"][$key] = (string)$value;
        }

        $textcontent = trim((string)$xmlnode);
        if (count($textcontent) > 0)
            $jsnode["_"] = $textcontent;

        foreach ($xmlnode->children() as $childxmlnode) {
            $childname = $childxmlnode->getName();
            if (!array_key_exists($childname, $jsnode))
                $jsnode[$childname] = array();
            array_push($jsnode[$childname], xml2js($childxmlnode, true));
        }
        return $jsnode;
    } else {
        $nodename = $xmlnode->getName();
        $jsnode[$nodename] = array();
        array_push($jsnode[$nodename], xml2js($xmlnode, true));
        return json_encode($jsnode);
    }
}   

ตัวอย่างการใช้งาน:

$xml = simplexml_load_file("myfile.xml");
echo xml2js($xml);

ตัวอย่างอินพุต (myfile.xml):

<family name="Johnson">
    <child name="John" age="5">
        <toy status="old">Trooper</toy>
        <toy status="old">Ultrablock</toy>
        <toy status="new">Bike</toy>
    </child>
</family>

ตัวอย่างผลลัพธ์:

{"family":[{"$":{"name":"Johnson"},"child":[{"$":{"name":"John","age":"5"},"toy":[{"$":{"status":"old"},"_":"Trooper"},{"$":{"status":"old"},"_":"Ultrablock"},{"$":{"status":"new"},"_":"Bike"}]}]}]}

พิมพ์สวย:

{
    "family" : [{
            "$" : {
                "name" : "Johnson"
            },
            "child" : [{
                    "$" : {
                        "name" : "John",
                        "age" : "5"
                    },
                    "toy" : [{
                            "$" : {
                                "status" : "old"
                            },
                            "_" : "Trooper"
                        }, {
                            "$" : {
                                "status" : "old"
                            },
                            "_" : "Ultrablock"
                        }, {
                            "$" : {
                                "status" : "new"
                            },
                            "_" : "Bike"
                        }
                    ]
                }
            ]
        }
    ]
}

ข้อควรจำ: แท็กหลายแท็กที่มีชื่อเดียวกันสามารถเป็นพี่น้องกันได้ โซลูชันอื่น ๆ มักจะทิ้งทั้งหมดยกเว้นพี่น้องคนสุดท้าย เพื่อหลีกเลี่ยงปัญหานี้แต่ละโหนดทุกโหนดแม้ว่าจะมีลูกเพียงคนเดียวก็คืออาร์เรย์ที่มีวัตถุสำหรับแต่ละอินสแตนซ์ของ tagname (ดูตัวอย่างองค์ประกอบหลายรายการ "")

แม้แต่องค์ประกอบรูทซึ่งควรมีอยู่เพียงหนึ่งเดียวเท่านั้นในเอกสาร XML ที่ถูกต้องจะถูกเก็บเป็นอาร์เรย์ที่มีวัตถุของอินสแตนซ์เพียงเพื่อให้มีโครงสร้างข้อมูลที่สอดคล้องกัน

เพื่อให้สามารถแยกความแตกต่างระหว่างเนื้อหาโหนด XML และแอตทริบิวต์ XML แต่ละแอตทริบิวต์ของวัตถุจะถูกเก็บไว้ใน "$" และเนื้อหาใน "_" ลูก

แก้ไข: ฉันลืมแสดงเอาต์พุตสำหรับข้อมูลอินพุตตัวอย่างของคุณ

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}

สามารถแยกวิเคราะห์ข้อมูล XML ขนาดใหญ่ได้หรือไม่
Volatil3

2
วิธีนี้ดีกว่าเพราะไม่ละทิ้งคุณลักษณะ XML ดูเพิ่มเติมว่าทำไมโครงสร้างที่ซับซ้อนนี้จะดีกว่าคนที่เรียบง่ายที่ xml.com/lpt/a/1658 (ดู "กึ่งโครงสร้าง XML") .... Ops สำหรับ CDATA เป็น @txyoji $xml = simplexml_load_file("myfile.xml",'SimpleXMLElement',LIBXML_‌​NOCDATA);แนะนำให้แผ่องค์ประกอบ
Peter Krauss

ขอบคุณมากสำหรับฟังก์ชั่นที่กำหนดเอง! มันทำให้จูนง่ายมาก Btw เพิ่มเวอร์ชันที่แก้ไขของฟังก์ชันของคุณที่แยกวิเคราะห์ XML ด้วยวิธี JS: ทุกรายการมีวัตถุของตัวเอง (รายการจะไม่ถูกจัดเก็บในอาร์เรย์เดียวหากพวกเขามี tagnames เท่ากัน) ดังนั้นคำสั่งจะถูกเก็บไว้
lucifer63

1
เกิดข้อผิดพลาดFatal error: Uncaught Error: Call to a member function getName() on bool.. ฉันคิดว่า php เวอร์ชันล้มเหลว :-( .. โปรดช่วยด้วย!
KingRider

10

ข้อผิดพลาดทั่วไปคือการลืมที่json_encode()ไม่เคารพองค์ประกอบที่มีค่าข้อความและคุณลักษณะ มันจะเลือกหนึ่งในนั้นหมายถึง dataloss ฟังก์ชั่นด้านล่างแก้ปัญหานั้น หากใครตัดสินใจที่จะไปเพื่อjson_encode/ decodeวิธีฟังก์ชั่นดังต่อไปนี้จะแนะนำ

function json_prepare_xml($domNode) {
  foreach($domNode->childNodes as $node) {
    if($node->hasChildNodes()) {
      json_prepare_xml($node);
    } else {
      if($domNode->hasAttributes() && strlen($domNode->nodeValue)){
         $domNode->setAttribute("nodeValue", $node->textContent);
         $node->nodeValue = "";
      }
    }
  }
}

$dom = new DOMDocument();
$dom->loadXML( file_get_contents($xmlfile) );
json_prepare_xml($dom);
$sxml = simplexml_load_string( $dom->saveXML() );
$json = json_decode( json_encode( $sxml ) );

โดยการทำเช่นนั้น<foo bar="3">Lorem</foo>จะไม่สิ้นสุดเช่นเดียวกับ{"foo":"Lorem"}ใน JSON ของคุณ


ไม่คอมไพล์และไม่สร้างเอาต์พุตที่อธิบายไว้หากข้อผิดพลาดทางไวยากรณ์ถูกแก้ไข
Richard Kiefer

คือ$domอะไร ไหนว่ามาจากไหน?
Jake Wilson

$ dom = DOMDocument ใหม่ (); มาจากไหน
สกอตต์

1
บรรทัดสุดท้ายของรหัส: $ json = json_decode (json_encode ($ sxml))); ควรเป็น: $ json = json_decode (json_encode ($ sxml));
Charlie Smith

6

ลองใช้สิ่งนี้

$xml = ... // Xml file data

// first approach
$Json = json_encode(simplexml_load_string($xml));

---------------- OR -----------------------

// second approach
$Json = json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA));

echo $Json;

หรือ

คุณสามารถใช้ห้องสมุดนี้: https://github.com/rentpost/xml2array


3

ฉันใช้TypeConverterของ Miles Johnson เพื่อจุดประสงค์นี้ มันสามารถติดตั้งได้โดยใช้นักแต่งเพลง

คุณสามารถเขียนสิ่งนี้โดยใช้:

<?php
require 'vendor/autoload.php';
use mjohnson\utility\TypeConverter;

$xml = file_get_contents("file.xml");
$arr = TypeConverter::xmlToArray($xml, TypeConverter::XML_GROUP);
echo json_encode($arr);

3

การเพิ่มประสิทธิภาพคำตอบอันโตนิโอแม็กซ์:

$xmlfile = 'yourfile.xml';
$xmlparser = xml_parser_create();

// open a file and read data
$fp = fopen($xmlfile, 'r');
//9999999 is the length which fread stops to read.
$xmldata = fread($fp, 9999999);

// converting to XML
$xml = simplexml_load_string($xmldata, "SimpleXMLElement", LIBXML_NOCDATA);

// converting to JSON
$json = json_encode($xml);
$array = json_decode($json,TRUE);

4
ฉันใช้วิธีนี้ แต่ JSON ว่างเปล่า XML นั้นถูกต้อง
ryabenko-pro

2

หากคุณต้องการแปลงเฉพาะบางส่วนของ XML เป็น JSON คุณสามารถใช้ XPath เพื่อดึงข้อมูลนี้และแปลงเป็น JSON

<?php
$file = @file_get_contents($xml_File, FILE_TEXT);
$xml = new SimpleXMLElement($file);
$xml_Excerpt = @$xml->xpath('/states/state[@id="AL"]')[0]; // [0] gets the node
echo json_encode($xml_Excerpt);
?>

โปรดทราบว่าถ้าคุณ Xpath ไม่ถูกต้องสิ่งนี้จะตายด้วยข้อผิดพลาด ดังนั้นหากคุณทำการดีบักผ่านการโทร AJAX ฉันขอแนะนำให้คุณบันทึกเนื้อหาของการตอบกลับด้วย


2
This is better solution

$fileContents= file_get_contents("https://www.feedforall.com/sample.xml");
$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
$fileContents = trim(str_replace('"', "'", $fileContents));
$simpleXml = simplexml_load_string($fileContents);
$json = json_encode($simpleXml);
$array = json_decode($json,TRUE);
return $array;

2

ทางออกที่ดีที่สุดซึ่งใช้งานได้อย่างมีเสน่ห์

$fileContents= file_get_contents($url);

$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);

$fileContents = trim(str_replace('"', "'", $fileContents));

$simpleXml = simplexml_load_string($fileContents);

//$json = json_encode($simpleXml); // Remove // if you want to store the result in $json variable

echo '<pre>'.json_encode($simpleXml,JSON_PRETTY_PRINT).'</pre>';

แหล่ง


1

นี่คือการปรับปรุงโซลูชัน upvoted ที่สุดโดย Antonio Max ซึ่งทำงานกับ XML ที่มีเนมสเปซ (โดยแทนที่โคลอนด้วยเครื่องหมายขีดล่าง) นอกจากนี้ยังมีตัวเลือกพิเศษบางอย่าง (และแยกวิเคราะห์<person my-attribute='name'>John</person>ได้อย่างถูกต้อง)

function parse_xml_into_array($xml_string, $options = array()) {
    /*
    DESCRIPTION:
    - parse an XML string into an array
    INPUT:
    - $xml_string
    - $options : associative array with any of these keys:
        - 'flatten_cdata' : set to true to flatten CDATA elements
        - 'use_objects' : set to true to parse into objects instead of associative arrays
        - 'convert_booleans' : set to true to cast string values 'true' and 'false' into booleans
    OUTPUT:
    - associative array
    */

    // Remove namespaces by replacing ":" with "_"
    if (preg_match_all("|</([\\w\\-]+):([\\w\\-]+)>|", $xml_string, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $xml_string = str_replace('<'. $match[1] .':'. $match[2], '<'. $match[1] .'_'. $match[2], $xml_string);
            $xml_string = str_replace('</'. $match[1] .':'. $match[2], '</'. $match[1] .'_'. $match[2], $xml_string);
        }
    }

    $output = json_decode(json_encode(@simplexml_load_string($xml_string, 'SimpleXMLElement', ($options['flatten_cdata'] ? LIBXML_NOCDATA : 0))), ($options['use_objects'] ? false : true));

    // Cast string values "true" and "false" to booleans
    if ($options['convert_booleans']) {
        $bool = function(&$item, $key) {
            if (in_array($item, array('true', 'TRUE', 'True'), true)) {
                $item = true;
            } elseif (in_array($item, array('false', 'FALSE', 'False'), true)) {
                $item = false;
            }
        };
        array_walk_recursive($output, $bool);
    }

    return $output;
}

2
หนึ่งไม่ได้ใช้ Regex เพื่อแยกวิเคราะห์ XML เว้นแต่ว่ามันเป็น XML ที่เรียบง่ายที่มีโครงสร้างเล็ก ๆ น้อย ๆ และข้อมูลที่คาดการณ์ได้มาก ฉันไม่สามารถความเครียดพอวิธีนี้แก้ปัญหาไม่ดี ข้อมูล BREAKS นี้ ไม่ต้องพูดถึงว่ามันช้าอย่างไม่น่าเชื่อ (คุณแยกวิเคราะห์ด้วย regex แล้วคุณแยกวิเคราะห์อีกครั้งหรือไม่) และไม่จัดการแท็กปิดตัวเอง
AlexanderMP

ฉันไม่คิดว่าคุณจะดูที่ฟังก์ชั่นจริงๆ มันไม่ได้ใช้ regex ในการทำการแยกวิเคราะห์ที่แท้จริงเพียงเพื่อแก้ไขการจัดการกับเนมสเปซซึ่งทำงานกับกรณี xml ทั้งหมดของฉันและการทำงานนั้นเป็นสิ่งที่สำคัญที่สุดแทนที่จะเป็น "ถูกต้องทางการเมือง" คุณยินดีที่จะปรับปรุงหากคุณต้องการ!
TheStoryCoder

2
ความจริงที่ว่ามันได้ผลสำหรับคุณไม่ได้หมายความว่าถูกต้อง มันเป็นรหัสเช่นนี้ที่สร้างบั๊กที่ยากต่อการวินิจฉัยและสร้างการหาประโยชน์ ฉันหมายถึงแม้แต่การดูข้อมูลจำเพาะ XML อย่างพิถีพิถันบนไซต์เช่นw3schools.com/xml/xml_elements.aspนี้แสดงเหตุผลมากมายว่าทำไมโซลูชันนี้จึงใช้งานไม่ได้ อย่างที่ฉันบอกว่ามันล้มเหลวในการตรวจจับแท็กปิดตัวเองเช่น<element/>ไม่สามารถระบุองค์ประกอบที่ขึ้นต้นด้วยหรือมีขีดล่างซึ่งได้รับอนุญาตใน XML ไม่สามารถตรวจพบ CDATA และอย่างที่ฉันบอกไปมันช้า มันเป็นความซับซ้อน O (n ^ 2) เนื่องจากการแยกวิเคราะห์ภายใน
AlexanderMP

1
สิ่งหนึ่งคือการจัดการกับเนมสเปซไม่ได้ถามที่นี่และมีวิธีที่เหมาะสมในการจัดการกับเนมสเปซ มีเนมสเปซเป็นสิ่งก่อสร้างที่มีประโยชน์ไม่ควรแยกวิเคราะห์เช่นนั้นและกลายเป็นสิ่งที่น่ารังเกียจที่จะไม่ถูกดำเนินการโดยตัวแยกวิเคราะห์ที่เหมาะสม และสิ่งที่คุณต้องทำก็คือไม่สร้างคู่แข่งเพื่อรับรางวัล "อัลกอริธึมที่ช้าที่สุดในปี 2016" แต่ต้องค้นหาสักเล็กน้อยเพื่อหาวิธีแก้ปัญหาจริง ๆ เช่นstackoverflow.com/อันนี้คำถาม / 16412047 / …และเรียกสิ่งนี้ว่าการปรับปรุงหรือไม่ ว้าว.
AlexanderMP

0

การแก้ปัญหาทั้งหมดที่นี่มีปัญหา!

... เมื่อการแสดงต้องการการตีความ XML ที่สมบูรณ์แบบ (ไม่มีปัญหาเกี่ยวกับคุณลักษณะ) และการทำซ้ำทั้งหมด text-tag-text-tag-text -... และลำดับของแท็ก นอกจากนี้โปรดจำไว้ว่าที่นี่วัตถุ JSON "เป็นชุดที่ไม่ได้เรียงลำดับ" (ไม่ใช่คีย์ซ้ำและคีย์ไม่สามารถมีลำดับที่กำหนดไว้ล่วงหน้าได้) ... แม้กระทั่งxml2json ของ ZFก็ผิด (!) เพราะไม่รักษาโครงสร้าง XML อย่างแน่นอน

โซลูชันทั้งหมดที่นี่มีปัญหากับ XML แบบง่ายนี้

    <states x-x='1'>
        <state y="123">Alabama</state>
        My name is <b>John</b> Doe
        <state>Alaska</state>
    </states>

... โซลูชัน @FTav ดูเหมือนจะดีกว่าโซลูชัน 3 บรรทัด แต่ก็มีข้อผิดพลาดเล็กน้อยเมื่อทดสอบด้วย XML นี้

วิธีการแก้ปัญหาแบบเก่าคือวิธีที่ดีที่สุด (สำหรับตัวแทนที่ลดความสูญเสีย)

วิธีการแก้ปัญหาในวันนี้ที่รู้จักกันดีในฐานะjsonMLจะถูกใช้โดยโครงการแดนซ์และอื่น ๆ และถูกนำเสนอเป็นครั้งแรกใน ~ ~ 2006 หรือ 2007 โดย (แยกต่างหาก) สตีเฟ่น McKameyและจอห์น Snelson

// the core algorithm is the XSLT of the "jsonML conventions"
// see  https://github.com/mckamey/jsonml
$xslt = 'https://raw.githubusercontent.com/mckamey/jsonml/master/jsonml.xslt';
$dom = new DOMDocument;
$dom->loadXML('
    <states x-x=\'1\'>
        <state y="123">Alabama</state>
        My name is <b>John</b> Doe
        <state>Alaska</state>
    </states>
');
if (!$dom) die("\nERROR!");
$xslDoc = new DOMDocument();
$xslDoc->load($xslt);
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($dom);

ผลิต

["states",{"x-x":"1"},
    "\n\t    ",
    ["state",{"y":"123"},"Alabama"],
    "\n\t\tMy name is ",
    ["b","John"],
    " Doe\n\t    ",
    ["state","Alaska"],
    "\n\t"
]

ดูhttp://jsonML.orgหรือgithub.com/mckamey/jsonml กฎการผลิตของ JSON นี้ขึ้นอยู่กับองค์ประกอบ JSON-analog

ป้อนคำอธิบายรูปภาพที่นี่

ไวยากรณ์นี้เป็นองค์ประกอบ
element-list ::= element ',' element-list | elementความหมายและการเกิดขึ้นอีกด้วย


2
โครงสร้าง XML ที่ผิดปกติมากที่ฉันสงสัยว่าจะมีกรณีการใช้ชีวิตจริง
TheStoryCoder

0

หลังจากค้นคว้าคำตอบทั้งหมดเล็กน้อยฉันก็พบกับโซลูชันที่ใช้งานได้ดีกับฟังก์ชั่น JavaScript ของฉันในเบราว์เซอร์ (รวมถึงคอนโซล / เครื่องมือ Dev):

<?php

 // PHP Version 7.2.1 (Windows 10 x86)

 function json2xml( $domNode ) {
  foreach( $domNode -> childNodes as $node) {
   if ( $node -> hasChildNodes() ) { json2xml( $node ); }
   else {
    if ( $domNode -> hasAttributes() && strlen( $domNode -> nodeValue ) ) {
     $domNode -> setAttribute( "nodeValue", $node -> textContent );
     $node -> nodeValue = "";
    }
   }
  }
 }

 function jsonOut( $file ) {
  $dom = new DOMDocument();
  $dom -> loadXML( file_get_contents( $file ) );
  json2xml( $dom );
  header( 'Content-Type: application/json' );
  return str_replace( "@", "", json_encode( simplexml_load_string( $dom -> saveXML() ), JSON_PRETTY_PRINT ) );
 }

 $output = jsonOut( 'https://boxelizer.com/assets/a1e10642e9294f39/b6f30987f0b66103.xml' );

 echo( $output );

 /*
  Or simply 
  echo( jsonOut( 'https://boxelizer.com/assets/a1e10642e9294f39/b6f30987f0b66103.xml' ) );
 */

?>

โดยทั่วไปจะสร้าง DOMDocument ใหม่โหลดและไฟล์ XML ลงในนั้นและสำรวจผ่านแต่ละโหนดและเด็ก ๆ ที่ได้รับข้อมูล / พารามิเตอร์และส่งออกไปยัง JSON โดยไม่มีเครื่องหมาย "@" ที่น่ารำคาญ

ลิงก์ไปยังไฟล์XML


0

โซลูชันนี้จัดการเนมสเปซแอ็ตทริบิวต์และสร้างผลลัพธ์ที่สอดคล้องกับองค์ประกอบการทำซ้ำ (ในอาร์เรย์เสมอแม้ว่าจะมีการเกิดขึ้นเพียงครั้งเดียว) แรงบันดาลใจจากratfactor ของ sxiToArray ()

/**
 * <root><a>5</a><b>6</b><b>8</b></root> -> {"root":[{"a":["5"],"b":["6","8"]}]}
 * <root a="5"><b>6</b><b>8</b></root> -> {"root":[{"a":"5","b":["6","8"]}]}
 * <root xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><a>123</a><wsp:b>456</wsp:b></root> 
 *   -> {"root":[{"xmlns:wsp":"http://schemas.xmlsoap.org/ws/2004/09/policy","a":["123"],"wsp:b":["456"]}]}
 */
function domNodesToArray(array $tags, \DOMXPath $xpath)
{
    $tagNameToArr = [];
    foreach ($tags as $tag) {
        $tagData = [];
        $attrs = $tag->attributes ? iterator_to_array($tag->attributes) : [];
        $subTags = $tag->childNodes ? iterator_to_array($tag->childNodes) : [];
        foreach ($xpath->query('namespace::*', $tag) as $nsNode) {
            // the only way to get xmlns:*, see https://stackoverflow.com/a/2470433/2750743
            if ($tag->hasAttribute($nsNode->nodeName)) {
                $attrs[] = $nsNode;
            }
        }

        foreach ($attrs as $attr) {
            $tagData[$attr->nodeName] = $attr->nodeValue;
        }
        if (count($subTags) === 1 && $subTags[0] instanceof \DOMText) {
            $text = $subTags[0]->nodeValue;
        } elseif (count($subTags) === 0) {
            $text = '';
        } else {
            // ignore whitespace (and any other text if any) between nodes
            $isNotDomText = function($node){return !($node instanceof \DOMText);};
            $realNodes = array_filter($subTags, $isNotDomText);
            $subTagNameToArr = domNodesToArray($realNodes, $xpath);
            $tagData = array_merge($tagData, $subTagNameToArr);
            $text = null;
        }
        if (!is_null($text)) {
            if ($attrs) {
                if ($text) {
                    $tagData['_'] = $text;
                }
            } else {
                $tagData = $text;
            }
        }
        $keyName = $tag->nodeName;
        $tagNameToArr[$keyName][] = $tagData;
    }
    return $tagNameToArr;
}

function xmlToArr(string $xml)
{
    $doc = new \DOMDocument();
    $doc->loadXML($xml);
    $xpath = new \DOMXPath($doc);
    $tags = $doc->childNodes ? iterator_to_array($doc->childNodes) : [];
    return domNodesToArray($tags, $xpath);
}

ตัวอย่าง:

php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}

นี้ใช้งานได้จริงสำหรับกรณีที่หลาย namespace ดีกว่าโซลูชั่นอื่น ๆ ทำไมมีการโหวตลง ...
แอรอน

0

พบว่าคำตอบของ FTav มีประโยชน์มากที่สุดเพราะปรับแต่งได้มาก แต่ฟังก์ชั่นxml2jsของเขามีข้อบกพร่องบางอย่าง ตัวอย่างเช่นหากองค์ประกอบของเด็กมี tagnames เท่ากันทั้งหมดจะถูกเก็บไว้ในวัตถุเดียวนั่นหมายความว่าลำดับขององค์ประกอบจะไม่ได้รับการเก็บรักษาไว้ ในบางกรณีเราต้องการรักษาความสงบเรียบร้อยดังนั้นเราจึงควรเก็บข้อมูลทุกองค์ประกอบไว้ในวัตถุแยกต่างหาก:

function xml2js($xmlnode) {
    $jsnode = array();
    $nodename = $xmlnode->getName();
    $current_object = array();

    if (count($xmlnode->attributes()) > 0) {
        foreach($xmlnode->attributes() as $key => $value) {
            $current_object[$key] = (string)$value;
        }
    }

    $textcontent = trim((string)$xmlnode);
    if (strlen($textcontent) > 0) {
        $current_object["content"] = $textcontent;
    }

    if (count($xmlnode->children()) > 0) {
        $current_object['children'] = array();
        foreach ($xmlnode->children() as $childxmlnode) {
            $childname = $childxmlnode->getName();
            array_push($current_object['children'], xml2js($childxmlnode, true));
        }
    }

    $jsnode[ $nodename ] = $current_object;
    return $jsnode;
}

นี่คือวิธีการทำงาน โครงสร้าง xml เริ่มต้น:

<some-tag some-attribute="value of some attribute">
  <another-tag>With text</another-tag>
  <surprise></surprise>
  <another-tag>The last one</another-tag>
</some-tag>

ผลลัพธ์ JSON:

{
    "some-tag": {
        "some-attribute": "value of some attribute",
        "children": [
            {
                "another-tag": {
                    "content": "With text"
                }
            },
            {
                "surprise": []
            },
            {
                "another-tag": {
                    "content": "The last one"
                }
            }
        ]
    }
}

-1

ดูเหมือนว่า$state->nameตัวแปรกำลังถืออาเรย์ คุณสามารถใช้ได้

var_dump($state)

ภายในforeachเพื่อทดสอบว่า

หากเป็นกรณีที่คุณสามารถเปลี่ยนสายภายในforeachเพื่อ

$states[]= array('state' => array_shift($state->name)); 

เพื่อแก้ไข


ดูเหมือนว่าคุณลักษณะเป็นอาร์เรย์ แต่ไม่ใช่ $ state-> name
Bryan Hadlock

-1
$templateData =  $_POST['data'];

// initializing or creating array
$template_info =  $templateData;

// creating object of SimpleXMLElement
$xml_template_info = new SimpleXMLElement("<?xml version=\"1.0\"?><template></template>");

// function call to convert array to xml
array_to_xml($template_info,$xml_template_info);

//saving generated xml file
 $xml_template_info->asXML(dirname(__FILE__)."/manifest.xml") ;

// function defination to convert array to xml
function array_to_xml($template_info, &$xml_template_info) {
    foreach($template_info as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_template_info->addChild($key);
                if(is_array($value)){
                    $cont = 0;
                    foreach(array_keys($value) as $k){
                        if(is_numeric($k)) $cont++;
                    }
                }

                if($cont>0){
                    for($i=0; $i < $cont; $i++){
                        $subnode = $xml_body_info->addChild($key);
                        array_to_xml($value[$i], $subnode);
                    }
                }else{
                    $subnode = $xml_body_info->addChild($key);
                    array_to_xml($value, $subnode);
                }
            }
            else{
                array_to_xml($value, $xml_template_info);
            }
        }
        else {
            $xml_template_info->addChild($key,$value);
        }
    }
}

มันเป็นโซลูชั่นที่มีขนาดเล็กและเป็นสากลโดยใช้อาร์เรย์ของข้อมูลที่สามารถแปลงเป็น JSON json_decode ... lucky
Octavio Perez Gallegos

2
คำถามนี้จะตอบคำถามเดิมได้อย่างไร? คำตอบของคุณดูเหมือนจะซับซ้อนกว่าคำถามเดิมและดูเหมือนจะไม่พูดถึง JSON ด้วยซ้ำ
Dan R

-1

หากคุณเป็นผู้ใช้ Ubuntu ติดตั้งตัวอ่าน xml (ฉันมี php 5.6. หากคุณมีอื่น ๆ โปรดหาแพ็คเกจและติดตั้ง)

sudo apt-get install php5.6-xml
service apache2 restart

$fileContents = file_get_contents('myDirPath/filename.xml');
$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
$fileContents = trim(str_replace('"', "'", $fileContents));
$oldXml = $fileContents;
$simpleXml = simplexml_load_string($fileContents);
$json = json_encode($simpleXml);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.