草庐IT

php - 带有 php 或 python 属性的 xml 到 json

coder 2024-01-05 原文

我正在尝试将一些 XML 转换为 JSON,这使用 PHP 很容易

$file = file_get_contents('data.xml' );
$a = json_decode(json_encode((array) simplexml_load_string($file)),1);
print_r($a);

获取以下 XML

<?xml version="1.0" encoding="UTF-8"?>
<foo>
    <bar>
        <one lang="fr" type="bar">Test</one>
        <one lang="fr" type="foo">Test</one>
        <one lang="fr" type="baz">Test</one>
    </bar>

    <thunk>
        <thud>
            <bar lang="fr" name="bob">test</bar>
            <bar lang="bz" name="frank">test</bar>
            <bar lang="ar" name="alive">test</bar>
            <bar lang="fr" name="bob">test</bar>
        </thud>
    </thunk>

</foo>

然后通过 simplexml 将其配对生成

Array
(
    [bar] => Array
        (
            [one] => Array
                (
                    [0] => Test
                    [1] => Test
                    [2] => Test
                )

        )

    [thunk] => Array
        (
            [thud] => Array
                (
                    [bar] => Array
                        (
                            [0] => test
                            [1] => test
                            [2] => test
                            [3] => test
                        )

                )

        )

)

理想情况下输出应该是这样的

{
    "foo": {
        "bar": {
            "one": [
                {
                    "_lang": "fr",
                    "_type": "bar",
                    "__text": "Test"
                },
                {
                    "_lang": "fr",
                    "_type": "foo",
                    "__text": "Test"
                },
                {
                    "_lang": "fr",
                    "_type": "baz",
                    "__text": "Test"
                }
            ]
        },
        "thunk": {
            "thud": {
                "bar": [
                    {
                        "_lang": "fr",
                        "_name": "bob",
                        "__text": "test"
                    },
                    {
                        "_lang": "bz",
                        "_name": "frank",
                        "__text": "test"
                    },
                    {
                        "_lang": "ar",
                        "_name": "alive",
                        "__text": "test"
                    },
                    {
                        "_lang": "fr",
                        "_name": "bob",
                        "__text": "test"
                    }
                ]
            }
        }
    }
}

问题是输出不包含子元素的所有属性,其中一些元素包含两个或多个属性,有没有办法用 PHP 或 Python 转换 xml 并包含在所有元素中找到的所有属性 children ?

谢谢

最佳答案

在我的回答中,我将介绍 PHP,特别是 SimpleXMLElement,它已经是您代码的一部分。

使用 SimpleXMLElement 对 XML 进行 JSON 编码的基本方法与您在问题中所采用的方法类似。您实例化 XML 对象,然后对其进行json_encode ( Demo ):

$xml = new SimpleXMLElement($buffer);
echo json_encode($xml, JSON_PRETTY_PRINT);

这会产生一个输出关闭但与您正在寻找的不完全相同。因此,您在这里使用 simplexml 所做的是更改 json_encode 编码 XML 对象的标准方式。

这可以通过实现 JsonSerializable 接口(interface)的 SimpleXMLElement 的新子类型来完成。下面是这样一个类,它具有 PHP 如何对对象进行 JSON 序列化的默认方式:

class JsonSerializer extends SimpleXmlElement implements JsonSerializable
{
    /**
     * SimpleXMLElement JSON serialization
     *
     * @return null|string
     *
     * @link http://php.net/JsonSerializable.jsonSerialize
     * @see JsonSerializable::jsonSerialize
     */
    function jsonSerialize()
    {
        return (array) $this;
    }
}

使用它将产生完全相同的输出 ( Demo ):

$xml = new JsonSerializer($buffer);
echo json_encode($xml, JSON_PRETTY_PRINT);

现在有趣的部分来了,只更改这些位的序列化以获得输出。

首先,您需要区分它是携带其他元素(有子元素)的元素还是您想要其属性和文本值的叶元素:

    if (count($this)) {
        // serialize children if there are children
        ...
    } else {
        // serialize attributes and text for a leaf-elements
        foreach ($this->attributes() as $name => $value) {
            $array["_$name"] = (string) $value;
        }
        $array["__text"] = (string) $this;
    }

通过这个 if/else 就完成了。 if-block 用于子元素,else-block 用于叶元素。由于叶元素更简单,我将它们保留在上面的示例中。正如您在 else-block 中看到的那样,它遍历所有属性并添加前缀为“_”的名称,最后添加“__text"通过转换为字符串输入。

子元素的处理有点复杂,因为您需要区分只有名称的单个子元素或需要内部额外数组的具有相同名称的多个子元素:

        // serialize children if there are children
        foreach ($this as $tag => $child) {
            // child is a single-named element -or- child are multiple elements with the same name - needs array
            if (count($child) > 1) {
                $child = [$child->children()->getName() => iterator_to_array($child, false)];
            }
            $array[$tag] = $child;
        }

现在序列化需要处理另一种特殊情况。您对根元素名称进行编码。因此,此例程需要检查该条件(即所谓的 document-element)(与 SimpleXML Type Cheatsheet 比较)并在某些情况下序列化为该名称:

    if ($this->xpath('/*') == array($this)) {
        // the root element needs to be named
        $array = [$this->getName() => $array];
    }

最后剩下要做的就是返回数组:

    return $array;

这是一个 JsonSerializer 一起编译的,在 simplexml 中根据您的需要量身定制。这里是类及其调用:

class JsonSerializer extends SimpleXmlElement implements JsonSerializable
{
    /**
     * SimpleXMLElement JSON serialization
     *
     * @return null|string
     *
     * @link http://php.net/JsonSerializable.jsonSerialize
     * @see JsonSerializable::jsonSerialize
     */
    function jsonSerialize()
    {
        if (count($this)) {
            // serialize children if there are children
            foreach ($this as $tag => $child) {
                // child is a single-named element -or- child are multiple elements with the same name - needs array
                if (count($child) > 1) {
                    $child = [$child->children()->getName() => iterator_to_array($child, false)];
                }
                $array[$tag] = $child;
            }
        } else {
            // serialize attributes and text for a leaf-elements
            foreach ($this->attributes() as $name => $value) {
                $array["_$name"] = (string) $value;
            }
            $array["__text"] = (string) $this;
        }

        if ($this->xpath('/*') == array($this)) {
            // the root element needs to be named
            $array = [$this->getName() => $array];
        }

        return $array;
    }
}

$xml = new JsonSerializer($buffer);
echo json_encode($xml, JSON_PRETTY_PRINT);

输出(Demo):

{
    "foo": {
        "bar": {
            "one": [
                {
                    "_lang": "fr",
                    "_type": "bar",
                    "__text": "Test"
                },
                {
                    "_lang": "fr",
                    "_type": "foo",
                    "__text": "Test"
                },
                {
                    "_lang": "fr",
                    "_type": "baz",
                    "__text": "Test"
                }
            ]
        },
        "thunk": {
            "thud": {
                "bar": [
                    {
                        "_lang": "fr",
                        "_name": "bob",
                        "__text": "test"
                    },
                    {
                        "_lang": "bz",
                        "_name": "frank",
                        "__text": "test"
                    },
                    {
                        "_lang": "ar",
                        "_name": "alive",
                        "__text": "test"
                    },
                    {
                        "_lang": "fr",
                        "_name": "bob",
                        "__text": "test"
                    }
                ]
            }
        }
    }
}

希望对您有所帮助。一次可能有点多,您可以找到 JsonSerializable interface documented in the PHP manual as well ,您可以在那里找到更多示例。 Stackoverflow 上使用这种 XML 到 JSON 转换的另一个例子可以在这里找到:XML to JSON conversion in PHP SimpleXML

关于php - 带有 php 或 python 属性的 xml 到 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31272929/

有关php - 带有 php 或 python 属性的 xml 到 json的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  6. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  7. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  8. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  9. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  10. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

随机推荐