PHP-XML: How do I modify text value of a given target

<?xml version="1.0" encoding="utf-8" ?>
<xliff>
    <body>
        <trans-unit id="NFDBB2FA9-tu4" xml:space="preserve">
            <source xml:lang="en">He</source>
            <target xml:lang="id">He</target>
        </trans-unit>
        <trans-unit id="NFDBB2FA9-tu5" xml:space="preserve">
            <source xml:lang="en">She</source>
            <target xml:lang="id">She</target>
        </trans-unit>
    </body>
    <body>
        <trans-unit id="NFDBB2FA9-tu6" xml:space="preserve">
            <source xml:lang="en">They</source>
            <target xml:lang="id">They</target>
        </trans-unit>
        <trans-unit id="NFDBB2FA9-tu7" xml:space="preserve">
            <source xml:lang="en">We</source>
            <target xml:lang="id">We</target>
        </trans-unit>
    </body>
</xliff>

how do I modify value of <target> of trans-unit id="NFDBB2FA9-tu7" or any other?

done this but empty on the print_r and don't know what's next

$dom = new \DOMDocument();
$dom->load("my.xlf");
$root = $dom->documentElement;
$xliffBodies = $root->getElementsByTagName("body")->item(0);

foreach ($xliffBody as $body) {
    $el = $body->getElementsByTagName("trans-unit");
    print_r($el);
}

1 answer

  • answered 2021-02-27 15:03 Professor Abronsius

    The code below is using a string representation of the original XML file (my.xlf) for convenience - change the loadXML for load to load your file.

    If you use an XPath expression you can target these elements directly - though here I targeted the trans-unit node initially before selecting the child node - target

    <?php
    
        $strxml='<?xml version="1.0" encoding="utf-8" ?>
    <xliff>
        <body>
            <trans-unit id="NFDBB2FA9-tu4" xml:space="preserve">
                <source xml:lang="en">He</source>
                <target xml:lang="id">He</target>
            </trans-unit>
            <trans-unit id="NFDBB2FA9-tu5" xml:space="preserve">
                <source xml:lang="en">She</source>
                <target xml:lang="id">She</target>
            </trans-unit>
        </body>
        <body>
            <trans-unit id="NFDBB2FA9-tu6" xml:space="preserve">
                <source xml:lang="en">They</source>
                <target xml:lang="id">They</target>
            </trans-unit>
            <trans-unit id="NFDBB2FA9-tu7" xml:space="preserve">
                <source xml:lang="en">We</source>
                <target xml:lang="id">We</target>
            </trans-unit>
        </body>
    </xliff>';
    
        $dom=new DOMDocument;
        $dom->loadXML($strxml);
        
        $xp=new DOMXPath($dom);
        $xp->registerNamespace('xml','http://www.example.com');
        
        $col=$xp->query( '//xliff/body/trans-unit' );
        if( $col && $col->length ){
            foreach( $col as $node ){
                $target=$xp->query('target',$node)->item(0);
                $target->nodeValue='banana';
            }
        }
        
        printf('<textarea cols=50 rows=10>%s</textarea>',$dom->saveXML());
    
    ?>
    

    A simple edit - change the target value to the word banana yields:

    Example output

    The original snippet of XML is a little different from the actual XML in that there are namespace declarations which mean you need to adopt a slightly different approach. More Information on Namespaces

    The default namespace needs to be used in the query, like so:

    <?php
    
        $id='NFDBB2FA9-tu26';
        
        $file='my.xlf';
    
        $dom=new DOMDocument;
        $dom->load( $file );
        
        $xp=new DOMXPath( $dom );
        # We need to use this in the XPath query - this could be almost anything but best kept short!!
        $xp->registerNamespace('f','urn:oasis:names:tc:xliff:document:1.2');
        
        # Not essential to declare the following when simply querying against the default namespace
        $xp->registerNamespace('okp','okapi-framework:xliff-extensions');
        $xp->registerNamespace('its','http://www.w3.org/2005/11/its');
        $xp->registerNamespace('itsxlf','http://www.w3.org/ns/its-xliff/');
        $xp->registerNamespace('xml','http://www.example.com');
        
        # note how each portion of the XPath expression uses our namespace prefix..
        $col=$xp->query( '//f:xliff/f:file/f:body/f:trans-unit[@id="'.$id.'"]/f:target' );
        
        
        
        if( $col && $col->length ){
            foreach( $col as $node ){
                $node->nodeValue='Big Bold Brave Banana';
            }
        }
        
        printf('<textarea cols=180 rows=40>%s</textarea>',$dom->saveXML());
    
    ?>