Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
689 views
in Technique[技术] by (71.8m points)

XSLT to remove duplicate while concating

My XML looks like following:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<BATCHES>
    <item>
        <Material>1000000079</Material>
        <Description>330 Bulk</Description>
        <Tank>T123</Tank>
        <Batch>2013225287</Batch>
    </item>
    <item>
        <Material>1000000079</Material>
        <Description>330 Bulk</Description>
        <Tank>T123</Tank>
        <Batch>2013225301</Batch>
    </item>
    <item>
        <Material>1000000196</Material>
        <Description>340R Bulk</Description>
        <Tank>T700</Tank>
        <Batch>1000188378</Batch>
    </item>
    <item>
        <Material>1000002754</Material>
        <Description>43 Bulk</Description>
        <Tank>T515</Tank>
        <Batch>2013180125</Batch>
    </item>
    <item>
        <Material>1000002754</Material>
        <Description>43 Bulk</Description>
        <Tank>T515</Tank>
        <Batch>2013203124</Batch>
    </item>
    <item>
        <Material>1000002754</Material>
        <Description>43 Bulk</Description>
        <Tank>T515</Tank>
        <Batch>2013214839</Batch>
    </item>
    <item>
        <Material>1000002754</Material>
        <Description>OGA 72043 Bulk</Description>
        <Tank>T517</Tank>
        <Batch>2013214342</Batch>
    </item>
</BATCHES>

My XSLT looks like follwoing:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
    <xsl:template match="/">
        <Rowsets>
            <Rowset>
                <xsl:variable name="materials" select=".//item[Tank!='RECV' and Tank!='PARK'] "/>
                <xsl:for-each select="$materials">
                    <xsl:if test="generate-id(.)=                       generate-id($materials[Material=current()/Material])">
                        <Row>
                            <Material>
                                <xsl:value-of select="Material"/>
                            </Material>
                            <Description>
                                <xsl:value-of select="Description"/>
                            </Description>
                            <Value>
                                <xsl:for-each select="$materials[Material=current()/Material]/Tank">
                                    <xsl:if test="node()">
                                        <xsl:value-of select="concat(.,'||')"/>
                                    </xsl:if>
                                </xsl:for-each>
                            </Value>
                        </Row>
                    </xsl:if>
                </xsl:for-each>
            </Rowset>
        </Rowsets>
    </xsl:template>
</xsl:stylesheet>

The result of XSLT is:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Rowsets>
    <Rowset>
        <Row>
            <Material>1000000079</Material>
            <Description>330 Bulk</Description>
            <Value>T123||T123||</Value>
        </Row>
        <Row>
            <Material>1000000196</Material>
            <Description>340R Bulk</Description>
            <Value>T700||</Value>
        </Row>
        <Row>
            <Material>1000002754</Material>
            <Description>43 Bulk</Description>
            <Value>T515||T515||T515||T517||</Value>
        </Row>
    </Rowset>
</Rowsets>

My problem is in the field I dont want to concatenate Tank if it is repeated.

Sample should be:

<Row>
                <Material>1000002754</Material>
                <Description>43 Bulk</Description>
                <Value>T515||T517||</Value>
            </Row>

I tried various combinations but could not achieve it. Can anyone plz help?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If the XML getting bigger a key based solution (with xslt-1.0) would be better.

But to keel the solution mostly as it is, only have unique Tank value. You can add two templates:

<xsl:template match="item" mode="tank" />
<xsl:template match="item[not(Material = preceding::item/Material and Tank =  preceding::item/Tank)]" mode="tank" >
    <xsl:value-of select="Tank"/>
    <xsl:text>||</xsl:text>
</xsl:template>

This ignores any item which has same Material and same Tank value.

And apply this templates in replacement for the for-each loop in <Value>:

<xsl:apply-templates select="$materials[Material=current()/Material ]" mode="tank" />

Therefore try this:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
    <xsl:template match="/">
        <Rowsets>
            <Rowset>
                <xsl:variable name="materials" select=".//item[Tank!='RECV' and Tank!='PARK'] "/>
                <xsl:for-each select="$materials">
                    <xsl:if test="generate-id(.)= generate-id($materials[Material=current()/Material])">
                        <Row>
                            <Material>
                                <xsl:value-of select="Material"/>
                            </Material>
                            <Description>
                                <xsl:value-of select="Description"/>
                            </Description>
                            <Value>
                                <xsl:apply-templates select="$materials[Material=current()/Material ]" mode="tank" />
                            </Value>
                        </Row>
                    </xsl:if>
                </xsl:for-each>
            </Rowset>
        </Rowsets>
    </xsl:template>
    <xsl:template match="item" mode="tank" />
    <xsl:template match="item[not(Material = preceding::item/Material and Tank =  preceding::item/Tank)]" mode="tank" >
        <xsl:value-of select="Tank"/>
        <xsl:text>||</xsl:text>
    </xsl:template>

</xsl:stylesheet>

Which will generate the following output:

<Rowsets>
  <Rowset>
    <Row>
      <Material>1000000079</Material>
      <Description>330 Bulk</Description>
      <Value>T123||</Value>
    </Row>
    <Row>
      <Material>1000000196</Material>
      <Description>340R Bulk</Description>
      <Value>T700||</Value>
    </Row>
    <Row>
      <Material>1000002754</Material>
      <Description>43 Bulk</Description>
      <Value>T515||T517||</Value>
    </Row>
  </Rowset>
</Rowsets>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...