요소의 모든 값의 첫 번째 및 마지막 발생에 대한 컨텍스트 데이터를 생성합니다.

StackOverflow https://stackoverflow.com/questions/807578

  •  03-07-2019
  •  | 
  •  

문제

다음 XML이 주어지면 :

<container>
    <val>2</val>
    <id>1</id>
</container>
<container>
    <val>2</val>
    <id>2</id>
</container>
<container>
    <val>2</val>
    <id>3</id>
</container>
<container>
    <val>4</val>
    <id>1</id>
</container>
<container>
    <val>4</val>
    <id>2</id>
</container>
<container>
    <val>4</val>
    <id>3</id>
</container>

나는 같은 것을 돌려주고 싶다

2 - 1
2 - 3
4 - 1
4 - 3

노드 셋을 사용하여 다음을 통해 마지막 발생을 얻을 수있었습니다.

exsl:node-set($list)/container[not(val = following::val)]

그러나 나는 첫 번째를 얻는 방법을 알 수 없습니다.

도움이 되었습니까?

해결책

각각의 첫 번째와 마지막 사건 (문서 순서)을 얻으려면 "<val>"그룹, 당신은 an을 사용할 수 있습니다 <xsl:key> 이와 같이:

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

  <xsl:key name="ContainerGroupByVal" match="container" use="val" />

  <xsl:variable name="ContainerGroupFirstLast" select="//container[
    generate-id() = generate-id(key('ContainerGroupByVal', val)[1])
    or
    generate-id() = generate-id(key('ContainerGroupByVal', val)[last()])
  ]" />

  <xsl:template match="/">
    <xsl:for-each select="$ContainerGroupFirstLast">
      <xsl:value-of select="val" />
      <xsl:text> - </xsl:text>
      <xsl:value-of select="id" />
      <xsl:value-of select="'&#10;'" /><!-- LF -->
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

편집 #1 : 바로 분명하지 않을 수 있으므로 약간의 설명 :

  • 그만큼 <xsl:key> 모든 것을 반환합니다 <container> 주어진 노드 <val>. 당신은 사용합니다 key() 쿼리하는 기능.
  • 그만큼 <xsl:variable> 모든 일이 일어나는 곳입니다. 다음과 같이 읽습니다.
    • 각각 <container> 문서의 노드 ( "//container") 확인하다…
    • … 동일한 고유 ID가있는 경우 (generate-id()) 첫 번째 노드로 반환됩니다 key() 또는 마지막 노드가 반환되었습니다 key()
    • 어디 key('ContainerGroupByVal', val) 세트를 반환합니다 <container> 전류와 일치하는 노드 <val>
    • 고유 ID가 일치하는 경우 선택에 노드를 포함시킵니다.
  • 그만큼 <xsl:for-each> 출력을 수행합니다. 마찬가지로 <xsl:apply-templates>.

편집 #2 : Dimitre Novatchev가 주석에서 정당하게 지적했듯이, 당신은 "사용에주의해야합니다."//"XPath 속기. 당신이 그것을 피할 수 있다면, 당신이 그것을 피할 수 있다면, 그렇게하십시오. :

<containers>
  <container><!-- ... --></container>
  <container><!-- ... --></container>
  <container><!-- ... --></container>
</containers>

그런 다음 사용해야합니다. "/containers/container" 또는 "/*/container" 대신에 "//container".


편집 #3 : 위의 대체 구문은 다음과 같습니다.

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

  <xsl:key name="ContainerGroupByVal" match="container" use="val" />

  <xsl:variable name="ContainerGroupFirstLast" select="//container[
    count(
        .
      | key('ContainerGroupByVal', val)[1]
      | key('ContainerGroupByVal', val)[last()]
    ) = 2
  ]" />

  <xsl:template match="/">
    <xsl:for-each select="$ContainerGroupFirstLast">
      <xsl:value-of select="val" />
      <xsl:text> - </xsl:text>
      <xsl:value-of select="id" />
      <xsl:value-of select="'&#10;'" /><!-- LF -->
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

설명 : XPath Union 운영자 "|"인수를 노드 세트로 결합합니다. 정의상, 노드 세트에는 중복 노드가 포함될 수 없습니다.". | . | ."정확히 하나의 노드 (현재 노드)를 포함하는 노드 세트를 생성합니다.

즉, 현재 노드 ( ".")에서 Union 노드 세트를 만들면 "key(…)[1]"노드와"key(…)[last()]"노드, 노드 카운트는 현재 노드가 다른 두 노드 중 하나 인 경우 2가됩니다. 다른 모든 경우에는 카운트가 3이됩니다.

다른 팁

기초적인 xpath:

//container[position() = 1]  <- this is the first one
//container[position() = last()]  <- this is the last one

여기에 세트가 있습니다 xpath 기능 더 자세하게.

I. XSLT 1.0

기본적으로 Tomalak의 것과 동일한 솔루션이지만 더 이해할 수 있습니다. 또한 완료되므로 XML 문서와 변환을 복사하여 붙여 넣은 다음 좋아하는 XSLT IDE의 "변환"버튼을 누르기 만하면됩니다.:

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

    <xsl:key name="kContByVal" match="container"
     use="val"/>

    <xsl:template match="/*">
      <xsl:for-each select=
       "container[generate-id()
                 =
                  generate-id(key('kContByVal',val)[1])
                 ]
       ">

       <xsl:variable name="vthisvalGroup"
        select="key('kContByVal', val)"/>

       <xsl:value-of select=
        "concat($vthisvalGroup[1]/val,
              '-',
              $vthisvalGroup[1]/id,
              '&#xA;'
              )
      "/>
       <xsl:value-of select=
        "concat($vthisvalGroup[last()]/val,
              '-',
              $vthisvalGroup[last()]/id,
              '&#xA;'
              )
        "/>
      </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

이 변환이 원래로 제공 된 XML 문서에 적용될 때 (잘 형성되도록 편집 됨) :

<t>
    <container>
        <val>2</val>
        <id>1</id>
    </container>
    <container>
        <val>2</val>
        <id>2</id>
    </container>
    <container>
        <val>2</val>
        <id>3</id>
    </container>
    <container>
        <val>4</val>
        <id>1</id>
    </container>
    <container>
        <val>4</val>
        <id>2</id>
    </container>
    <container>
        <val>4</val>
        <id>3</id>
    </container>
</t>

원하는 결과가 생성됩니다:

2-1
2-3
4-1
4-3

주목하십시오:

  1. 우리는 그룹화에 Muenchian 방법을 사용합니다 하나를 찾으려면 container 동일한 값을 갖는 각 요소 세트에 대한 요소 val.
  2. 전체 노드 목록에서 container 동일 한 요소 val, 우리는 첫 번째 데이터에 필요한 데이터를 출력합니다 container 그룹의 요소와 마지막 요소 container 그룹의 요소.

II. XSLT 2.0

이 변형:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text"/>

    <xsl:template match="/*">
      <xsl:for-each-group select="container"
           group-by="val">
        <xsl:for-each select="current-group()[1], current-group()[last()]">
          <xsl:value-of select=
           "concat(val, '-', id, '&#xA;')"/>
        </xsl:for-each>
    </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

위와 동일한 XML 문서에 적용되면 원하는 결과를 프로디 로스:

2-1
2-3
4-1
4-3

주목하십시오:

  1. 사용 <xsl:for-each-group> XSLT 명령.

  2. 사용 current-group() 기능.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top