1

I am making a table where the header names are from the header element, and the data is obtained from the attributes of the reportdata elements. However, I do not know the names of the attributes: Value1, Value2, ect.. ahead of time. The names of the attributes are generated and stored into the FieldName attribute which is inside of the column elements inside of the reportnode.

I have not been able to find a way to make an XPath that uses the generated FieldNames and obtains the corresponding attribute's value from reportdata. Any ideas? Or is this not possible.

The following is the XML:

<report>
    <reportparameters>
        <header Order="1" HeaderName="Day_1" />
        <header Order="2" HeaderName="Day_2" />
        <header Order="3" HeaderName="Day_3" />
        <header Order="4" HeaderName="Total" />

        <reportnode ColumnCount="4">
            <column Order="1" FieldName="Value1" />
            <column Order="2" FieldName="Value2" />
            <column Order="3" FieldName="Value3" />
            <column Order="4" FieldName="TotalValue" />
        </reportnode>
    </reportparameters>

    <reportdata Value1="0" Value2="0" Value3="0" TotalValue="0"/>
    <reportdata Value1="0" Value2="0" Value3="0" TotalValue="0"/>
    <reportdata Value1="0" Value2="0" Value3="0" TotalValue="0"/>
    <reportdata Value1="0" Value2="0" Value3="0" TotalValue="0"/>
    <reportdata Value1="0" Value2="0" Value3="0" TotalValue="0"/>
</report>

The XSL attempt:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="no"/>
    <xsl:template match="/">
        <report>       
            <row>
                <xsl:for-each select="/report/reportparameters/header">
                    <xsl:variable name="columnCounter" select="position()"/>
                    <xsl:element name="{./@HeaderName}">
                    <xsl:for-each select="/report/reportdata">
                        <xsl:value-of select="@{../reportparameters/reportnode/column[@Order=$columnCounter+1]/@FieldName}"/>
                    </xsl:for-each>
                    </xsl:element>
                </xsl:for-each>
            </row>
        </report>
    </xsl:template>
</xsl:stylesheet>
2
  • 2
    What is the result that you are attempting to get? Please use distinct cell values so that we can understand the logic of the transformation. Commented Jun 14, 2017 at 23:10
  • @michael.hor257k I will definitely make sure I post my desired result next time. Luckily you were still able to help me without it! Commented Jun 15, 2017 at 16:04

1 Answer 1

2

I suspect you could do simply:

XSLT 1.0

<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="/report">
    <xsl:variable name="cols" select="reportparameters/reportnode/column" />
    <report> 
        <xsl:for-each select="reportdata">
            <row>
                <xsl:for-each select="@*">
                    <xsl:variable name="i" select="position()"/>
                    <xsl:element name="{$cols[$i]/@FieldName}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:for-each>
            </row>
        </xsl:for-each>
    </report>
</xsl:template>

</xsl:stylesheet>

to get:

<?xml version="1.0" encoding="UTF-8"?>
<report>
  <row>
    <Value1>0</Value1>
    <Value2>0</Value2>
    <Value3>0</Value3>
    <TotalValue>0</TotalValue>
  </row>
  <row>
    <Value1>0</Value1>
    <Value2>0</Value2>
    <Value3>0</Value3>
    <TotalValue>0</TotalValue>
  </row>
  <row>
    <Value1>0</Value1>
    <Value2>0</Value2>
    <Value3>0</Value3>
    <TotalValue>0</TotalValue>
  </row>
  <row>
    <Value1>0</Value1>
    <Value2>0</Value2>
    <Value3>0</Value3>
    <TotalValue>0</TotalValue>
  </row>
  <row>
    <Value1>0</Value1>
    <Value2>0</Value2>
    <Value3>0</Value3>
    <TotalValue>0</TotalValue>
  </row>
</report>

This is assuming every reportdata has the same attributes, in the same order, corresponding to the order of column elements in reportnode. Otherwise it gets slightly more complicated.

OTOH, if - as shown in your example - the attributes of reportdata have the required names, it can be even simpler:

<xsl:template match="/report">
    <report> 
        <xsl:for-each select="reportdata">
            <row>
                <xsl:for-each select="@*">
                    <xsl:element name="{name()}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:for-each>
            </row>
        </xsl:for-each>
    </report>
</xsl:template>
Sign up to request clarification or add additional context in comments.

1 Comment

The first solution worked well, but your second solution made me contemplate why I hadn't formatted my xml that way. I made some changes to the way I was building my XML so that it is more intuitive and now I can use your second solution. Thanks so much!

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.