How do I sort a list of XML items into rows for an

2019-08-02 20:25发布

I have the following XML:

<items>
  <item x="1" y="3"/>
  <item x="2" y="4"/>
  <item x="3" y="4"/>
  <item x="4" y="2"/>
  <item x="5" y="1"/>
</items>

I want to ultimately put them into an HTML table (the x and y are coordinates of cells in that table), and to make it easier I want to put the items into rows, like this:

<items>
  <row y="1">
    <item x="1" y="1"/>
  </row>
  <row y="2">
    <item x="2" y="2"/>
  </row>
  <row y="3">
    <item x="5" y="3"/>
  </row>
  <row y="4">
    <item x="3" y="4"/>
    <item x="4" y="4"/>
  </row>
</items>

But the only transform I can come up with not only doesn't work, but also doesn't allow me to annotate the rows with row number.

<xsl:template match="/items">
  <items>
    <row>
      <xsl:for-each select="item">
        <xsl:sort select="@y"/>
        <xsl:sort select="@x"/>

        <xsl:if test="preceding-sibling::item[1]/@y != @y">
          <xsl:text>"</row>"</xsl:text>
          <xsl:text>"<row>"</xsl:text>
        </xsl:if>
        <xsl:copy-of select="."/>
      </xsl:for-each>
    </row>  
  </items>
</xsl:template>

How can I accomplish this?

1条回答
Juvenile、少年°
2楼-- · 2019-08-02 20:43

Your posted XSLT isn't valid - a proper processor won't let you start and end tags like that in a way that could end up being invalid XML.

You need to group these - if you're using XSLT 1.0 you can use Muenchian grouping like so, although I'm not quite sure how to make sense of your expected output given your input:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" omit-xml-declaration="yes" indent="yes" />
  <xsl:key name="items-by-y" match="item" use="@y" />
  <xsl:template match="/items">
    <items>
      <xsl:for-each select="item[count(. | key('items-by-y', @y)[1]) =1]">
        <xsl:sort select="@y" />
        <xsl:sort select="@x" />
        <row y="{@y}">
          <xsl:for-each select="key('items-by-y', @y)">
            <xsl:copy-of select="." />
          </xsl:for-each>
        </row>
      </xsl:for-each>
    </items>
  </xsl:template>
</xsl:stylesheet>

results in:

<items>
    <row y="1">
        <item x="5" y="1"/>
    </row>
    <row y="2">
        <item x="4" y="2"/>
    </row>
    <row y="3">
        <item x="1" y="3"/>
    </row>
    <row y="4">
        <item x="2" y="4"/>
        <item x="3" y="4"/>
    </row>
</items>

If you're using XSLT 2.0, you could do something like <xsl:for-each-group>, see How to use for each group in XSL for more information.

查看更多
登录 后发表回答