Xslt XSL删除重复记录,考虑标记和值

Xslt XSL删除重复记录,考虑标记和值,xslt,duplicates,Xslt,Duplicates,考虑到标记/值,我想删除重复记录 以下是输入: <Details> <block order="1" title="Circle A" id="Circle"> <block id="square" title="Square 1" order="1"> <block id="d

考虑到标记/值,我想删除重复记录

以下是输入:

<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>
                <field order="4" title="D" id="ID d">45-34-YT</field>
                <field order="5" title="E" id="ID e">500</field>
                <field order="6" title="F" id="ID f">ABC</field>
                <field order="7" title="G" id="ID g">Street xpto</field>
                <field order="8" title="H" id="ID h">39RT</field>
                <field order="9" title="I" id="ID i">Working Closet</field>
            </block>
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>
                <field order="4" title="D" id="ID d">45-34-YT</field>
                <field order="5" title="E" id="ID e">500</field>
                <field order="6" title="F" id="ID f">ABC</field>
                <field order="7" title="G" id="ID g">Street xpto</field>
                <field order="8" title="H" id="ID h">39RT</field>
                <field order="9" title="I" id="ID i">Working Closet</field>
            </block>
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>
                <field order="4" title="D" id="ID d">45-34-YT</field>
                <field order="5" title="E" id="ID e">500</field>
                <field order="6" title="F" id="ID f">ABC</field>
                <field order="7" title="G" id="ID g">Street xpto</field>
                <field order="8" title="H" id="ID h">39RT</field>
                <field order="9" title="I" id="ID i">Working Closet</field>
            </block>            
        </block>
    </block>
</Details>

500
街道xpto
太阳
45-34-YT
500
基础知识
街道xpto
39RT
工作间
500
街道xpto
太阳
45-34-YT
500
基础知识
街道xpto
39RT
工作间
500
街道xpto
太阳
45-34-YT
500
基础知识
街道xpto
39RT
工作间
以下是期望输出:

<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>
                <field order="4" title="D" id="ID d">45-34-YT</field>
                <field order="5" title="E" id="ID e">500</field>
                <field order="6" title="F" id="ID f">ABC</field>
                <field order="7" title="G" id="ID g">Street xpto</field>
                <field order="8" title="H" id="ID h">39RT</field>
                <field order="9" title="I" id="ID i">Working Closet</field>
            </block>        
        </block>
    </block>
</Details>

500
街道xpto
太阳
45-34-YT
500
基础知识
街道xpto
39RT
工作间
我已尝试使用此xslt:

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
        <xsl:if test="not(preceding-sibling::node()[.=string(current())])">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

但我需要删除这些行:

<field order="5" title="E" id="ID e">500</field>
<field order="7" title="G" id="ID g">Street xpto</field>
500
街道xpto
因为我的xslt只考虑标记值。 我不知道如何考虑全行而不是只考虑价值。 有人能帮忙吗

谢谢。 何塞

更精确的样品。 例1: 输入:


500
街道xpto
500
500
街道xpto
500
500
街道xpto
500
输出:

<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">500</field>               
            </block>
        </block>
    </block>
</Details>
<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>               
            </block>
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street A</field>
                <field order="3" title="C" id="ID c">Sun</field>               
            </block>        
        </block>
    </block>
</Details>

500
街道xpto
500
结果:一个不同的块id“点”

例2: 第三个街区不同,因为第二个街区现在是“街道A” 输入:


500
街道xpto
500
500
街道xpto
500
500
A街
500
输出:

<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">500</field>               
            </block>
        </block>
    </block>
</Details>
<Details>
    <block order="1" title="Circle A" id="Circle">
        <block id="square" title="Square 1" order="1">
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street xpto</field>
                <field order="3" title="C" id="ID c">Sun</field>               
            </block>
            <block id="dot" title="test" order="1">
                <field order="1" title="A" id="ID a">500</field>
                <field order="2" title="B" id="ID b">Street A</field>
                <field order="3" title="C" id="ID c">Sun</field>               
            </block>        
        </block>
    </block>
</Details>

500
街道xpto
太阳
500
A街
太阳
结果:两个不同的块id为“点”

我希望这些新的样本有助于澄清我的伪装。
提前感谢您的回复和回答。

在XSLT 2或3中,您的需求可以用
deep equal
表达(当然还有身份转换):

我希望XSLT3的唯一用途是
,它应该被模板所取代

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

对于XSLT 1,我希望下面使用两个键就足够了:

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

  <xsl:key name="block" match="block[@id = 'dot']" use="concat(@title, '|', @order)"/>
  
  <xsl:key name="field" match="block[@id = 'dot']/field" use="concat(../@title, '|', ../@order, '|', @order, '|', @title, '|', @id, '|', .)"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template 
    match="block[@id = 'dot'][not(generate-id() = generate-id(key('block', concat(@title, '|', @order))[1]))][not(field[generate-id() = generate-id(key('field', concat(../@title, '|', ../@order, '|', @order, '|', @title, '|', @id, '|', .))[1])])]"/>

</xsl:stylesheet>


但我还没有完全测试过,我不确定这种方法是否遗漏了一些方面,比如子元素的顺序。

这可能是您需要的吗? 它使用块[field]的@id来查看它是否是唯一具有该@id的块[field]

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[field]">
    <xsl:variable name="id" select="@id"/>
    <xsl:if test="not( preceding-sibling::block[@id=$id])">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

2021年4月10日:在OP发布了更多的例子之后,我认为这应该能起到作用:

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[block[field]]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="block[1]"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[field]">
    <xsl:variable name="fields" select="normalize-space(.)"/>
    <xsl:if test="not(following-sibling::block[normalize-space(.)=$fields])">
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:copy-of select="field"/> 
      </xsl:copy>
    </xsl:if>
    <xsl:apply-templates select="following-sibling::block[1]"/>
  </xsl:template>

</xsl:stylesheet>


块之间的字段是否可能有任何不同?如果是这样的话,你能举个例子吗?如果你局限于XSLT1.0,那么就用XSLT1.0来代替现在效率低下的方法。这也将允许你使用一个键来连接所有你想考虑的值(哪些是你的问题不清楚的)。differ@michael.hor257k,我希望始终拥有唯一的
@JoseMartins,您使用或可以使用哪个XSLT处理器,哪个版本?
唯一内容的确切含义是什么?XPath2和更高版本的函数
deep equal
是否表达了这一要求?谢谢。快到了。但是这个解决方案不考虑字段标签值的变化,请检查我提出的新的样本。@何塞·马丁斯:请再试一次这个更新版本XSLT版本1。谢谢,但这不起作用。@ JojeMARTIN,对于哪个样本它不起作用?并且似乎给出了你想要的结果。它起作用了,我错误地复制了你的解决方案。谢谢。
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[field]">
    <xsl:variable name="id" select="@id"/>
    <xsl:if test="not( preceding-sibling::block[@id=$id])">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[block[field]]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="block[1]"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="block[field]">
    <xsl:variable name="fields" select="normalize-space(.)"/>
    <xsl:if test="not(following-sibling::block[normalize-space(.)=$fields])">
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:copy-of select="field"/> 
      </xsl:copy>
    </xsl:if>
    <xsl:apply-templates select="following-sibling::block[1]"/>
  </xsl:template>

</xsl:stylesheet>