0

I have an array of XML <row> elements each of which can then have an array of <query> elements. It looks something like this:

<row><query></query><query></query></row>
<row><query></query><query></query></row>
<row><query></query><query></query></row>
<row><query></query><query></query></row>

I want to print a table in case the query children are different across the row elements and a comma separated string if the query children are same across all the row children.

I am composing an <xsl:when> for this:

<xsl:choose>
  <xsl:when test="[Table condition]">
    <!--code to print table-->
  </xsl:when>
  <xsl:otherwise>
    <!--code to print string-->
  </xsl:otherwise>
</xsl:choose>

What should be the Table Condition?

I am using XSLT v 1.0. I know there is something called deep equals but don't understand how to use it here.

Can you help me here?

Core_Dumped
  • 4,577
  • 11
  • 47
  • 71
  • Sorry, don't understand what you need... Please provide sample data (within your empty XML structure) and the expected output. – Shnugo Nov 17 '15 at 08:28
  • Do you simply want to compare the number of child elements? Or their data as well? – Martin Honnen Nov 17 '15 at 08:40
  • @MartinHonnen I want to compare their data as well. The number of children are assumed to be always equal in all `row`s but the data may differ. – Core_Dumped Nov 17 '15 at 09:32
  • @Core_Dumped See: http://stackoverflow.com/questions/33610324/xslt-how-to-find-the-count-of-unique-children-of-a-node/33614575#33614575 – michael.hor257k Nov 17 '15 at 11:43

2 Answers2

1

deep-equal is a function introduced in XSLT/XPath 2.0, here is a sample using that (which then of course requires using an XSLT 2.0 processor like Saxon 9, Altova, XmlPrime):

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="table[not(row[some $sibling in ../row satisfies not(deep-equal(., $sibling))])]">
        <xsl:value-of select="row/query" separator=","/>
    </xsl:template>
</xsl:transform>

I have obviously put the condition for one case in a match pattern and simply let the copying of other tables work through the identity transformation.

With a sample input like

<root>
    <table>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
    </table>
    <table>
        <row><query>2</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
    </table>
</root>

the result is

<root>
    1,2,1,2,1,2,1,2
    <table>
        <row><query>2</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
        <row><query>1</query><query>2</query></row>
    </table>
</root>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Is there a way to do this in XSLT 1.0? I am using that. – Core_Dumped Nov 17 '15 at 10:12
  • Do you know the number of `query` elements when writing the XSLT code? – Martin Honnen Nov 17 '15 at 10:20
  • No, I do not. They may vary but the number of them is same for all the `row` elements – Core_Dumped Nov 17 '15 at 13:56
  • It is difficult with XSLT 1.0 to achieve the comparison if there can be an unknown number of `query` elements which additionally have complex contents. Maybe Dimitre Novatchev comes along later and feels challenged and is going to help you. I am more inclined to suggest to move to XSLT 2.0 in such cases where a lot of code is needed in XSLT 1.0 – Martin Honnen Nov 17 '15 at 14:04
  • I tried to change my stylesheet version to 2.0 (as suggested in http://stackoverflow.com/questions/9387396/upgrading-xslt-1-0-to-xslt-2-0) but I don't seem to use the XSLT 2.0 functionalities. Do I have to install a new XSL processor as well? If so, how? – Core_Dumped Nov 17 '15 at 14:15
  • Well options are Saxon 9, Altova (I am not sure they provide the processor as a standalone, you might need to install a trial version of their XML IDE XMLSpy) or XmlPrime. The open source version of Saxon 9, Saxon 9 HE comes in a Java and in a .NET version, see http://saxonica.com/welcome/welcome.xml for details about download, installation, documentation. – Martin Honnen Nov 17 '15 at 14:19
  • Yes, changing the version number in your stylesheet doesn't automagically convert your XSLT processor into a 2.0 processor. – Michael Kay Nov 17 '15 at 15:32
0

If there is only text inside your query elements, it shouldn't be too difficult in XSLT 1.0. For instance, I assume a sample of two rows might look like this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <row><query>foo</query><query>foo</query></row>
    <row><query>foo1</query><query>foo2</query></row>
</root>

If you process this data by an XSLT template like

<xsl:for-each select="//row">
        <xsl:choose>
            <xsl:when test="query[not(. = preceding-sibling::query or . = following-sibling::query)]">
                There is at least one query element which is different from the others
                in the same raw.
            </xsl:when>
            <xsl:otherwise>
                All query elements in this row are equal.
            </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>

you get the expected result: The first row is treated as "equal", the other as "different". This is done by checking if the preceding and following query: Is there at least one which is not both equal to all preceding and following siblings?

Is this more or less what you're looking for?

cis
  • 1,259
  • 15
  • 48
  • That is a dangerous comparison, no? If you have `abc` and `abc` then your comparison will give true although the values are different. – Martin Honnen Nov 17 '15 at 10:19
  • There is not necessarily text inside `query`. It might have one or more children. We can assume that the children across `row`s for the same position of `query` have the same tags but might not have the same value and that is what I am trying to compare. – Core_Dumped Nov 17 '15 at 10:20
  • @Martin Honnen, at least with Saxon 6 it returns "false" in both cases (as it should) @Core_Dumped: Well, in this case, my suggested solution won't work. A workaround could be to transform all content of `query` to a string and compare it afterwards. – cis Nov 17 '15 at 10:25