0
votes

Was trying the XSLTProcessor, but it breaks if I try adding attributes to elements with children

XSLTProcessor::transformToXml() [xsltprocessor.transformtoxml]: xsl:attribute: Cannot add attributes to an element if children have been already added to the element.

I will add that this very XSLT+XML are being parsed correctly on the client side.
Is there any PHP version/Parser that knows how to handle such a problem?

UPD:The I am using XSL is a third party we connect to, I have no control on what I get from there/them.

3

3 Answers

1
votes

When you add attributes to an element after adding children to the element, an XSLT 1.0 processor is allowed to either ignore the attributes, or report an error. You seem to have two processors that have chosen different options. Either way, the code is broken and needs fixing. (XSLT 2.0 requires the error to be reported.)

0
votes

XSLTProcessor is best choice for PHP. Try to avoid problematic syntax in templates. if I understand your task correctly, you can try something like this:

<xsl:template match="XPathOfYourElement">
    <someTag someAttribute='<xsl:value-of select="someXpath"/>'>
        <xsl:apply-templates/>
    </someTag>
</xsl:template>

Also you can use php4 xslt functions, but it's moveton.

Another way is using non-php console utilities for xslt transformations via shell_exec(), but it's a bad way too.

0
votes

It's also a problem with other parsers (MSXML, .NET System.XML).
Try to re-arrange the order in the XSL. You have to be explicit in where you want your element.

Here's a sample XML / XSL

<xml>
    <e>One</e>
    <e>Two</e>
    <e>Three</e>
</xml>

You can add both elements and attributes with the following XSL

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xml>
    <xsl:for-each select='/xml/e'>
        <xsl:element name='e'>
            <xsl:attribute name='newatt'>New attribute</xsl:attribute>
            <xsl:value-of select='.'/>
        </xsl:element>
        <xsl:element name='newlement'>
            <xsl:attribute name='newatt'>New attribute in new element</xsl:attribute>
            new element value
        </xsl:element>
    </xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>

Creates this

   <?xml version="1.0"?>
<xml>
  <e newatt="New attribute">One</e>
  <newlement newatt="New attribute in new element">
                        new element value
                </newlement>
  <e newatt="New attribute">Two</e>
  <newlement newatt="New attribute in new element">
                        new element value
                </newlement>
  <e newatt="New attribute">Three</e>
  <newlement newatt="New attribute in new element">
                        new element value
                </newlement>
</xml>