XSLT:忽略重复类似的值

时间:2017-07-06 17:19:03

标签: xml xslt

我正在使用XSLT,它具有使用(MySegment/*[not(.=preceding::*)]).

忽略重复项的逻辑

输入:

<MySegment>
  <Field1>ABCD</Field1>
  <FIeld2>1</Field2>
</MySegment>
<MySegment>
  <Field1>ABCD123</Field1>
  <FIeld2>1</Field2>
</MySegment>

这里我们有两个不同的值,但是由于ABCD123也包含ABCD,因此它被视为重复条目。任何人都可以提供建议。

以下是我的XSLT的样子:

<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="/RecordsInp">

    <xsl:for-each select="ParentSegment">

      <xsl:for-each select="./MySegment/*[not(.=preceding::*)]">

        <A>
          <Field1><xsl:value-of select ="name(.)"/></Field1>
          <Field2><xsl:value-of select="."/></Field2>
        </A>

      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

我的意见是:

<RecordsInp>
  <ParentSegment>
    <MySegment>
      <Field1>ABC</Field1>
      <Field2>A1</Field2>
    </MySegment>

    <MySegment>
      <Field1>ABC</Field1>
      <Field2>A1</Field2>
    </MySegment>

    <MySegment>
      <Field1>ABCDEF</Field1>
      <Field2>ABC</Field2>
    </MySegment>
  </ParentSegment>
</RecordsInp>

我得到的是:

 <?xml version="1.0" encoding="UTF-8"?>
    <A>
      <Field1>Field1</Field1>
      <Field2>ABC</Field2>
    </A><A>
      <Field1>Field2</Field1>
      <Field2>A1</Field2>
    </A><A>
      <Field1>Field1</Field1>
      <Field2>ABCDEF</Field2>
    </A>

注意我在最后一次出现时没有得到Field2 = ABC。由于Field2在之前的事件中从未有过ABC,我需要在XML下面:

<?xml version="1.0" encoding="UTF-8"?>
<A>
  <Field1>Field1</Field1>
  <Field2>ABC</Field2>
</A><A>
  <Field1>Field2</Field1>
  <Field2>A1</Field2>
</A><A>
  <Field1>Field1</Field1>
  <Field2>ABCDEF</Field2>
</A>
<A>
  <Field1>Field2</Field1>
  <Field2>ABC</Field2>
</A>

2 个答案:

答案 0 :(得分:0)

根据您的第二个输入示例,您的样式表未按预期方式提取<Field2>ABC</Field2>的原因是因为ABC作为前一个Field1中的值存在。

还可以根据谓词中的当前(current())名称测试名称,但也许你应该尝试使用xsl:keyMuenchian grouping)而不是preceding::轴...

XML输入

<RecordsInp>
    <ParentSegment>
        <MySegment>
            <Field1>ABC</Field1>
            <Field2>A1</Field2>
        </MySegment>
        <MySegment>
            <Field1>ABC</Field1>
            <Field2>A1</Field2>
        </MySegment>
        <MySegment>
            <Field1>ABCDEF</Field1>
            <Field2>ABC</Field2>
        </MySegment>
    </ParentSegment>
</RecordsInp>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="fields" match="MySegment/*" 
    use="concat(name(),'|',normalize-space())"/>

  <xsl:template match="MySegment">
    <xsl:for-each 
      select="*[count(.|key('fields',concat(name(),'|',normalize-space()))[1])=1]">
      <A>
        <Field1><xsl:value-of select="name()"/></Field1>
        <Field2><xsl:value-of select="."/></Field2>
      </A>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

<强>输出

<A>
   <Field1>Field1</Field1>
   <Field2>ABC</Field2>
</A>
<A>
   <Field1>Field2</Field1>
   <Field2>A1</Field2>
</A>
<A>
   <Field1>Field1</Field1>
   <Field2>ABCDEF</Field2>
</A>
<A>
   <Field1>Field2</Field1>
   <Field2>ABC</Field2>
</A>

答案 1 :(得分:0)

您的XPath表达式./MySegment/*[not(.=preceding::*)]选择每个上下文节点的<MySegment>个子元素的子元素,这些子元素的字符串值与文档顺序中的任何元素的字符串值不匹配。因此,由于前面的<Field2>ABC</Field2>元素,<Field1>ABC</Field1>未反映在结果中。

显然,这是一个比你想要的更广泛的条件;据我所知,你只想比较具有相同名称的前面的元素。在纯XPath中表达有点棘手;使用样式表重构更容易处理。无端使用xsl:for-each表明了这种重构。这是一个合理的方法:

<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="/RecordsInp/ParentSegment/MySegment/*">
    <!-- bind the context node's name and value to variables: -->
    <xsl:variable name="fname" select="name()"/>
    <xsl:variable name="fvalue" select="string(.)"/>

    <!-- here's the test you seem really to want: -->
    <xsl:if test="not(preceding::*[name() = $fname and string() = $fvalue])">
      <A>
        <Field1><xsl:value-of select ="$fname"/></Field1>
        <Field2><xsl:value-of select="$fvalue"/></Field2>
      </A>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>