0

I'm trying to transform (flatten) XML with multiple output using XSLT into XML with single output. But node which must be duplicated for each node is ignored. XML file has two outputs: HEAD and EXPERIMENT.

Source XML document:

<?xml version="1.0" encoding="utf-8"?>
<ELEMENT>
    <HEAD>
        <FIRSTNAME>Anton</FIRSTNAME>
        <SURNAME>Konchik</SURNAME>
        <REPORTDATE>01.01.2019</REPORTDATE>
    </HEAD>
    <EXPERIMENT>
        <NAME>EXPERIMENT1</NAME>
        <DATE>01.01.2018</DATE>
        <RESULT>POSITIVE</RESULT>
    </EXPERIMENT>
    <EXPERIMENT>
        <NAME>EXPERIMENT2</NAME>
        <DATE>01.01.2019</DATE>
        <RESULT>NEGATIVE</RESULT>
    </EXPERIMENT>
    <EXPERIMENT>
        <NAME>EXPERIMENT3</NAME>
        <DATE>01.01.2017</DATE>
        <RESULT>NOTSURE</RESULT>
    </EXPERIMENT>
</ELEMENT>

By using code below I want to duplicate HEAD node inside each EXPERIMENT node. XSLT transformation code:

<?xml version='1.0' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" version="2.0" encoding="UTF-8" />
    <xsl:template match="/">
        <xsl:element name="ELEMENT">
            <xsl:for-each select="ELEMENT/EXPERIMENT">
                <xsl:element name="EXPERIMENT">

                    <xsl:element name="NAME">
                          <xsl:value-of select="./NAME"/>
                    </xsl:element>

                    <xsl:element name="DATE">
                          <xsl:value-of select="./DATE"/>
                    </xsl:element>

                    <xsl:element name="RESULT">
                          <xsl:value-of select="./RESULT"/>
                    </xsl:element>

                        <xsl:for-each select="ELEMENT/HEAD">
                           <xsl:element name="FIRSTNAME">
                                  <xsl:value-of select="./FIRSTNAME"/>
                            </xsl:element>
                           <xsl:element name="SURNAME">
                                  <xsl:value-of select="./SURNAME"/>
                            </xsl:element>
                           <xsl:element name="REPORTDATE">
                                  <xsl:value-of select="./REPORTDATE"/>
                            </xsl:element>
                        </xsl:for-each>

                </xsl:element>          
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Excepted result:

<?xml version="1.0" encoding="utf-8"?>
<ELEMENT>
    <EXPERIMENT>
        <NAME>EXPERIMENT1</NAME>
        <DATE>01.01.2018</DATE>
        <RESULT>POSITIVE</RESULT>
        <FIRSTNAME>Anton</FIRSTNAME>
        <SURNAME>Konchik</SURNAME>
        <REPORTDATE>01.01.2019</REPORTDATE>
    </EXPERIMENT>
    <EXPERIMENT>
        <NAME>EXPERIMENT2</NAME>
        <DATE>01.01.2019</DATE>
        <RESULT>NEGATIVE</RESULT>
        <FIRSTNAME>Anton</FIRSTNAME>
        <SURNAME>Konchik</SURNAME>
        <REPORTDATE>01.01.2019</REPORTDATE>
    </EXPERIMENT>
    <EXPERIMENT>
        <NAME>EXPERIMENT3</NAME>
        <DATE>01.01.2017</DATE>
        <RESULT>NOTSURE</RESULT>
        <FIRSTNAME>Anton</FIRSTNAME>
        <SURNAME>Konchik</SURNAME>
        <REPORTDATE>01.01.2019</REPORTDATE>
    </EXPERIMENT>
</ELEMENT>

But HEAD node is ignored. Actual result:

<?xml version="1.0" encoding="utf-8"?>
<ELEMENT>
  <EXPERIMENT>
    <NAME>EXPERIMENT1</NAME>
    <DATE>01.01.2018</DATE>
    <RESULT>POSITIVE</RESULT>
  </EXPERIMENT>
  <EXPERIMENT>
    <NAME>EXPERIMENT2</NAME>
    <DATE>01.01.2019</DATE>
    <RESULT>NEGATIVE</RESULT>
  </EXPERIMENT>
  <EXPERIMENT>
    <NAME>EXPERIMENT3</NAME>
    <DATE>01.01.2017</DATE>
    <RESULT>NOTSURE</RESULT>
  </EXPERIMENT>
</ELEMENT>

Thanks for your help.

1 Answer 1

1

Change:

<xsl:for-each select="ELEMENT/HEAD">

to:

<xsl:for-each select="/ELEMENT/HEAD">

or:

<xsl:for-each select="../HEAD">

What you have is looking for ELEMENT that is a child of the current EXPERIMENT. What you need is to start at the root of the tree, or go up in the hierarchy.


Note also that you could do simply:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/ELEMENT">
    <xsl:copy>
        <xsl:for-each select="EXPERIMENT">
            <xsl:copy>
                <xsl:copy-of select="*"/>
                <xsl:copy-of select="../HEAD/*"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much, @michael.hor257k for explanation and working code! Have a nice day!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.