【问题标题】:PHP - How to delete from variable that contains XML structure some specific elements?PHP - 如何从包含 XML 结构的变量中删除某些特定元素?
【发布时间】:2013-03-24 00:38:39
【问题描述】:

我有一个字段 $xml 包含一些 XML 值。首先我必须提到,元素不是在新行(行)中分开,而是像没有新行的字符串一样绑定在一起。

我将首先展示 XML 结构看起来如何易于“阅读”。

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv=" http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <p:queryBillingAccountResponse xmlns:p=" http://www.ibm.com">
            <ns0:customerAccount xmlns:ns0=" http://www.ibm.com/xmlns/">
                <AccountStatus>Paid</AccountStatus>
                <ComponentCustomerAccount>
                    <Name>ADSL 4</Name>
                    <CharacteristicValue>
                        <Characteristic>
                            <Name>Balance</Name>
                        </Characteristic>
                        <Value>0.0</Value>
                    </CharacteristicValue>
                    <AccountStatus>Paid</AccountStatus>
                </ComponentCustomerAccount>
            </ns0:customerAccount>
        </p:queryBillingAccountResponse>
    </soapenv:Body>
</soapenv:Envelope>
<AccountStatus>Paid</AccountStatus>
</ComponentCustomerAccount>
</ns0:customerAccount>
</p:queryBillingAccountResponse>
</soapenv:Body>
</soapenv:Envelope>

但我再次必须提到 $xml 字段中的实际值并不那么容易阅读。 例如,它看起来像这样

<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv=" http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><p:queryBillingAccountResponse xmlns:p=" http://www.ibm.com">.......

我想删除元素:?xmlversion soapenv:Envelopesoapenv:Body 以及它们的属性。我想在 xml 值的开头和结尾删除它们。其他一切都保持原样1 如何实现这一目标?所以我在 php 字段中的新值应该从 queryBillingAccountResponse 元素开始。谢谢

【问题讨论】:

    标签: php xml


    【解决方案1】:

    对于有效的 XML,您可以使用 SimpeXMLDOMDocument 来查询 body 元素的子节点。

    $xml = '<?xml version="1.0" encoding="utf-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Body>
            <p:queryBillingAccountResponse xmlns:p="http://www.ibm.com">
                <ns0:customerAccount xmlns:ns0="http://www.ibm.com/xmlns/">
                    <AccountStatus>Paid</AccountStatus>
                    <ComponentCustomerAccount>
                        <Name>ADSL 4</Name>
                        <CharacteristicValue>
                            <Characteristic>
                                <Name>Balance</Name>
                            </Characteristic>
                            <Value>0.0</Value>
                        </CharacteristicValue>
                        <AccountStatus>Paid</AccountStatus>
                    </ComponentCustomerAccount>
                </ns0:customerAccount>
            </p:queryBillingAccountResponse>
        </soapenv:Body>
    </soapenv:Envelope>';
    
    $xml = simplexml_load_string($xml);
    $xml = $xml->xpath('//soapenv:Body/child::*')[0];
    echo $xml->asXML();
    

    结果是:

    <p:queryBillingAccountResponse xmlns:p="http://www.ibm.com">
        <ns0:customerAccount xmlns:ns0="http://www.ibm.com/xmlns/">
            <AccountStatus>Paid</AccountStatus>
            <ComponentCustomerAccount>
                <Name>ADSL 4</Name>
                <CharacteristicValue>
                    <Characteristic>
                        <Name>Balance</Name>
                    </Characteristic>
                    <Value>0.0</Value>
                </CharacteristicValue>
                <AccountStatus>Paid</AccountStatus>
            </ComponentCustomerAccount>
        </ns0:customerAccount>
    </p:queryBillingAccountResponse>
    

    但问题是您的 XML 无效,我不知道这是否是复制和粘贴错误。

    【讨论】:

    • 感谢您的回答。为什么你认为它不是 vaid 也许我没有看到一些解析错误?我应该将此 $xml = simplexml_load_string($xml);使用新的 simplexmlelement ???
    • 您的 XML 无效,因为它在结束标记的末尾包含额外的内容。此外,命名空间 URL 之前的空格无效。你是什​​么意思:我应该把这个 $xml = simplexml_load_string($xml);使用新的 simplexmlelement
    • 这是一个包含 xml 值的字符串字段,所以我的意思是我应该先用新的 simplexmlelement 启动它,然后才能使用其他一些函数来进一步解析该 xml。 (例如,我稍后需要 foreach 函数来进一步解析它)。所以我的问题是这是否足够 simplexml_load_string($xml);在该字符串字段中制作 xml 格式?谢谢
    • 函数simplexml_load_string 返回一个SimpleXMLElement 实例。现在有了这个实例,您可以遍历您的 XML。所以第一步应该是:从您的 XML 字符串创建一个 SimpleXMLElement 实例。然后使用 xpath 选择主体的子节点,如我在示例中所述。 $xml-&gt;xpath('//soapenv:Body/child::*') 为您提供SimpleXMLElement 实例的数组。因此,您可以遍历这些实例以进一步处理您的 XML。
    • 在 $xml = simplexml_load_string($xml); 之后$xml 是空的。这是因为无效的 XML - 如何在检索后将其更改为有效/谢谢
    【解决方案2】:

    这是使用 XSLT 最简单和最简单的方法:

    function extract_body_stripns($xmlstring) {
        static $xsl = NULL;
        if ($xsl === NULL) {
            $xsl_soap_body_nons = <<<'EOT'
    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0"
      xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:output encoding="UTF-8" method="xml" />
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="*[namespace-uri()]" priority="1">
        <xsl:element name="{local-name()}">
          <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
      </xsl:template>
    
      <xsl:template match="@*[namespace-uri()]" priority="1">
        <xsl:attribute name="{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:template>
    
      <xsl:template match="/">
        <xsl:apply-templates select="/soapenv:Envelope/soapenv:Body/*"/>
      </xsl:template>
    </xsl:stylesheet>
    EOT;
    
            $style = new DOMDocument();
            $style->loadXML($xsl_soap_body_nons, LIBXML_COMPACT | LIBXML_NOBLANKS | LIBXML_NONET);
            $xsl = new XSLTProcessor();
            $xsl->importStylesheet($style);
            unset($style);
        }
        $d = new DOMDocument();
        $d->loadXML($xmlstring, LIBXML_COMPACT | LIBXML_NONET);
        $newd = $xsl->transformToDoc($d);
        unset($d);
        return $newd->saveXML($newd->documentElement);
    }
    

    使用此功能:

    echo extract_body_stripns($xmlString);
    

    结果是:

    <queryBillingAccountResponse>
            <customerAccount>
                <ComponentCustomerAccount>
                    <Name>ADSL 4</Name>
                    <CharacteristicValue>
                        <Characteristic>
                            <Name>Balance</Name>
                        </Characteristic>
                        <Value>0.0</Value>
                    </CharacteristicValue>
                    <AccountStatus>Paid</AccountStatus>
                </ComponentCustomerAccount>
            </customerAccount>
        </queryBillingAccountResponse>
    

    请注意,如果您的源文档中有命名空间属性,那么剥离命名空间的过程可能会导致您丢失其中的一些属性。例如。使用&lt;myelement ns:myattrib="a" myattrib="b"/&gt;元素,你的一个属性会丢失,你会丢失哪个属性不一致!

    【讨论】:

    • 你好,谢谢你的回答,但我不希望在最终的 xml 中有这个属性。ADSL 4 我们可以实现一些现在将向我们显示属性的东西像您的 ADSL 4 示例中的元素。谢谢
    • 那是我添加到你的xml来测试属性处理代码的一个属性,忘记删除了。如果您实际使用您的 xml 在您的机器上运行此代码,您将看到没有添加任何属性。
    【解决方案3】:

    你可以使用 ereg_replace http://php.net/manual/en/function.ereg-replace.php

    使用正则表达式来识别要删除的元素。

    【讨论】:

    • ereg_ 函数自 PHP 5.3 起已弃用,但更重要的是使用正则表达式进行 html/xml 解析 that way madness lies....
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多