Pergunta

Eu preciso obter o conteúdo HTML de answer Neste pedaço de XML:

<qa>
 <question>Who are you?</question>
 <answer>Who who, <strong>who who</strong>, <em>me</em></answer>
</qa>

Então, eu quero pegar a string "quem, u003Cstrong>quem, quemu003C/strong> , u003Cem>euu003C/em> ".

Se eu tiver o answer como um SimpleXMLElement, Eu posso ligar asXML() para obter "u003Canswer> Quem, u003Cstrong>quemu003C/strong> eu, u003Cem>euu003C/em>u003C/answer> ", Mas como obter o XML interno de um elemento sem o próprio elemento envolvido em torno dele?

Eu preferiria maneiras de não envolver funções de string, mas se essa é a única maneira, que assim seja.

Foi útil?

Solução

Que eu saiba, não há uma maneira interna de conseguir isso. Eu recomendo tentar SimpleDom, que é uma classe PHP que estende o SimplexMleLement que oferece métodos de conveniência para a maioria dos problemas comuns.

include 'SimpleDOM.php';

$qa = simpledom_load_string(
    '<qa>
       <question>Who are you?</question>
       <answer>Who who, <strong>who who</strong>, <em>me</em></answer>
    </qa>'
);
echo $qa->answer->innerXML();

Caso contrário, vejo duas maneiras de fazer isso. O primeiro seria converter seu SimpleXMLElement para um DOMNode Em seguida, passe sobre o seu childNodes Para construir o XML. O outro seria ligar asXML() Em seguida, use as funções da string para remover o nó raiz. Atenção, porém, asXML() às vezes pode devolver a marcação que é realmente fora do nó que foi chamado, como XML Prolog ou Processing Instructions.

Outras dicas

function SimpleXMLElement_innerXML($xml)
  {
    $innerXML= '';
    foreach (dom_import_simplexml($xml)->childNodes as $child)
    {
        $innerXML .= $child->ownerDocument->saveXML( $child );
    }
    return $innerXML;
  };

Isso funciona (embora pareça realmente coxo):

echo (string)$qa->answer;

A solução mais direta é implementar o GET INNERXML personalizado com XML simples:

function simplexml_innerXML($node)
{
    $content="";
    foreach($node->children() as $child)
        $content .= $child->asXml();
    return $content;
}

No seu código, substitua $body_content = $el->asXml(); com $body_content = simplexml_innerXML($el);

No entanto, você também pode mudar para outra API que oferece distinção entre o InnerXML (o que você está procurando) e o Outerxml (o que você ganha agora). O Microsoft Dom Libary oferece essa distinção, mas infelizmente o PHP DOM não.

Descobri que a API do PHP XMLReader oferece essa distinção. Consulte ReadInnerxml (). Embora essa API tenha uma abordagem bem diferente para processar o XML. Tente.

Por fim, enfatizaria que o XML não pretende extrair dados como subárvores, mas como valor. É por isso que você está tendo problemas para encontrar a API certa. Seria mais 'padrão' armazenar a subárvore HTML como um valor (e escapar de todas as tags) em vez da subárvore XML. Também tenha cuidado que algum sintáx HTML nem sempre são compatíveis com XML (ou seja,
vs,
). De qualquer forma, na prática, sua abordagem é definitivamente mais conveniente para editar o arquivo XML.

Eu teria estendido a aula SimpXMLELEMENT:

class MyXmlElement extends SimpleXMLElement{

    final public function innerXML(){
        $tag = $this->getName();
        $value = $this->__toString();
        if('' === $value){
            return null;
        }
        return preg_replace('!<'. $tag .'(?:[^>]*)>(.*)</'. $tag .'>!Ums', '$1', $this->asXml());
    }
}

E então use assim:

echo $qa->answer->innerXML();
<?php
    function getInnerXml($xml_text) {           
        //strip the first element
        //check if the strip tag is empty also
        $xml_text = trim($xml_text);
        $s1 = strpos($xml_text,">");        
        $s2 = trim(substr($xml_text,0,$s1)); //get the head with ">" and trim (note that string is indexed from 0)

        if ($s2[strlen($s2)-1]=="/") //tag is empty
            return "";

        $s3 = strrpos($xml_text,"<"); //get last closing "<"        
        return substr($xml_text,$s1+1,$s3-$s1-1);
    }

    var_dump(getInnerXml("<xml />"));
    var_dump(getInnerXml("<xml  /  >faf <  / xml>"));
    var_dump(getInnerXml("<xml      ><  / xml>"));    
    var_dump(getInnerXml("<xml>faf <  / xml>"));
    var_dump(getInnerXml("<xml  >  faf <  / xml>"));      
?>

Depois de procurar um tempo, não obtive uma solução satisfatória. Então eu escrevi minha própria função. Esta função terá exato exato innerXml conteúdo (incluindo espaço em branco, é claro). Para usá -lo, passe o resultado da função asXML(), assim getInnerXml($e->asXML()). Essa função funciona para elementos com muitos prefixos também (como meu caso, pois não consegui encontrar nenhum método atual que faça a conversão em todo o nó infantil de diferentes prefixos).

Resultado:

string '' (length=0)    
string '' (length=0)    
string '' (length=0)    
string 'faf ' (length=4)    
string '  faf ' (length=6)
    function get_inner_xml(SimpleXMLElement $SimpleXMLElement)
    {
        $element_name = $SimpleXMLElement->getName();
        $inner_xml = $SimpleXMLElement->asXML();
        $inner_xml = str_replace('<'.$element_name.'>', '', $inner_xml);
        $inner_xml = str_replace('</'.$element_name.'>', '', $inner_xml);
        $inner_xml = trim($inner_xml);
        return $inner_xml;
    }

Se você não deseja tirar a seção CDATA, comente as linhas 6-8.

function innerXML($i){
    $text=$i->asXML();
    $sp=strpos($text,">");
    $ep=strrpos($text,"<");
    $text=trim(($sp!==false && $sp<=$ep)?substr($text,$sp+1,$ep-$sp-1):'');
    $sp=strpos($text,'<![CDATA[');
    $ep=strrpos($text,"]]>");
    $text=trim(($sp==0 && $ep==strlen($text)-3)?substr($text,$sp+9,-3):$text);
    return($text);
}

Você pode simplesmente usar esta função :)

function innerXML( $node )
{
    $name = $node->getName();
    return preg_replace( '/((<'.$name.'[^>]*>)|(<\/'.$name.'>))/UD', "", $node->asXML() );
}

Usando regex, você pode fazer isso

preg_match(’/<answer(.*)?>(.*)?<\/answer>/’, $xml, $match);
$result=$match[0];
print_r($result);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top