skip to Main Content

Suppose I have a XML file with a structure unknown to me. But I know that somewhere in that xml structure, one node has a known value, for instance, {1} as in node->nodeValue="{1}".

How can I create another XML file, identical to the first one, but with that value {1} replaced with another value (‘New value’)?

Here’s what I’ve tried, without sucess:

    $xmlfile=$this->xmlPath.'document1.xml';
    $xmlwfile=$this->xmlPath.'document2.xml';
    $this->xml = new XMLReader();
    $this->xml->open($xmlfile);

    $this->wxml = new DOMDocument();
    
    while($this->xml->read())
    {
        $node = $this->xml->expand();

        if($this->xml->nodeType == XMLReader::TEXT) 
        {
            if(str_contains($this->xml->value,"{1}"))
            {
                $node->nodeValue='New Value';
            }
        }
        
        $this->wxml->appendChild($this->wxml->importNode($node, true));            
    }
    
    $this->wxml->save($xmlwfile); 
    
    $this->xml->close();

Any thoughts?
Thanks,
Pedro

2

Answers


  1. Here is XSLT based solution that is using a so called Identity Transform pattern.

    You just need to launch XSLT transformation in php.

    Input XML

    <?xml version="1.0"?>
    <root>
        <foo>whatever</foo>
        <moo>cow</moo>
    </root>
    

    XSLT

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" omit-xml-declaration="no"
                    encoding="UTF-8" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:param name="findme" select="'whatever'"/>
        <xsl:param name="replaceWith" select="'newvalue'"/>
    
        <!--Identity transform-->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="foo[text()=$findme]">
            <xsl:copy>
                <xsl:value-of select="$replaceWith"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    Output XML

    <?xml version='1.0' encoding='UTF-8'?>
    <root>
      <foo>newvalue</foo>
      <moo>cow</moo>
    </root>
    
    Login or Signup to reply.
  2. XMLReader/XMLWriter are used for large XMLs. For "normal" documents, DOM is easier because it loads the whole document and allows you to use Xpath expressions to fetch nodes.

    $document = new DOMDocument();
    $document->loadXML(getTemplateString());
    $xpath = new DOMXpath($document);
    
    $searchFor = '{1}';
    $replaceWith = 'New Value';
    
    // all text nodes that are equal to searchFor after whitespace normalization
    $expression = '//text()[normalize-space(.) = "'.$searchFor.'"]';
    
    foreach ($xpath->evaluate($expression) as $textNode) {
        $textNode->textContent = $replaceWith;
        
    }
    
    echo $document->saveXML();
    
    
    function getTemplateString(): string {
        return <<<'XML'
    <?xml version="1.0"?>
    <root>
        <foo>{1}</foo>
        <bar>42</bar>
    </root>
    XML;
    }
    

    Output:

    <?xml version="1.0"?>
    <root>
        <foo>New Value</foo>
        <bar>42</bar>
    </root>
    XML;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search