문제

XML 문서를 변환하려고합니다. 내 XML 변환은 특정 요소의 값에 따라 두 가지 유형의 기본 요소를 초래할 수 있습니다.

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'">
      <xsl:call-template name="StructureA">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="StructureB">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

그런 다음 구조적 또는 구조 B는 자체 네임 스페이스 및 회로도로 만들어집니다.

<StructureA xmlns="http://...">

Structurea & B는 몇 가지 공통 요소를 공유하므로 두 구조물에 템플릿이 포함 된 "xmlcommon.xslt"라는 별도의 파일로 정의됩니다. 이 xmlcommon 파일에는 structurea 또는 structureb에 정의 된 네임 스페이스에서 사용할 수 있기를 원하는 기본 네임 스페이스가 없습니다. 그러나 내 변환을 실행하면 공통 파일에서 가져온 템플릿이 빈 xmlns 속성을 초래합니다.

<StructureA xmlns="http://...">
  <SharedElement xmlns="">Something</SharedElement>
</StructureA>

검증 할 때 빈 네임 스페이스가 올바른 부모 대신 사용됩니다. 공통 파일의 템플릿이 빈 XMLNS 속성을 추가하지 못하게하는 방법을 아는 사람이 있습니까?

다음은 공통 파일의 스 니펫입니다.

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="ControlledListStructure">
    <xsl:param name="xmlElem" />
    <xsl:param name="structure" />

    <xsl:element name="{$xmlElem}">
      <!-- Blah blah blah -->
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
도움이 되었습니까?

해결책

깨달아야 할 핵심은 스타일 시트가 결과 트리에 추가 한 각 요소의 이름을 지시한다는 것입니다. 요소의 이름에는 로컬 이름과 네임 스페이스 URI의 두 부분이 있습니다. 위의 코드에서 로컬 이름 (값 $xmlElem),하지만 네임 스페이스 URI를 지정하지 않으므로 빈 문자열로 기본값을받습니다. (실제로, 그것은 해당 스타일 시트 모듈의 기본 네임 스페이스를 가져옵니다. 없기 때문에 빈 문자열입니다.) 다시 말해서 요소는 다음과 같습니다. 네임 스페이스가 아닙니다. 문서를 직렬화 할 때 XSLT 프로세서에는 xmlns="" 상단에 나타나는 기본 네임 스페이스를 사용하지 않도록 선언하지 않습니다. 그렇지 않으면, 요소는 해당 네임 스페이스를 취할 것입니다. 이는 스타일 시트가 지시 한 것이 아닙니다. 이것을 해결하는 가장 방해가 가장 적은 방법은 다른 매개 변수를 추가하는 것입니다 (예 : $namespaceURI), 당신이 가진 것처럼 $xmlElem. 그런 다음 쓸 것입니다.

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}">

이제 결과 요소는 귀하가 취해야한다고 말하는 네임 스페이스를 취합니다 (이는 기본 네임 스페이스를 제거하는 효과가 있습니다).

그것은 당신의 질문에 대답해야합니다. 나는 무료 보너스 자료로 다음을 제공합니다. ;-)

당신은 제거해야합니다 text() 값 비교의 노드 테스트. 텍스트 노드의 값을 직접 비교할 필요는 거의 없습니다. 대신, 요소 자체의 문자열 값을 비교할 수 있습니다 (모든 후손 텍스트 노드의 문자열 값의 연결로 정의 됨). 그것은 다음과 같습니다.

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'">

이런 식으로 수행하는 장점은 의견이 숨겨져 있으면 코드가 중단되지 않는다는 것입니다.

<value>2<!--test-->00</value>

이 경우 두 개의 텍스트 노드 ( "2"및 "00")가 있습니다. 원래 테스트는 실패합니다. 왜냐하면 그 중 하나가 "200"과 같은지 확인하기 때문입니다. 이 경우에는 발생할 가능성이 높지 않지만 어쨌든 텍스트 노드 어린이와 반대되는 요소의 문자열 값을 테스트하는 것이 귀하의 의도 일 때 좋은 관행입니다.

마지막으로 템플릿 규칙과 XPath 컨텍스트에 대해 배우는 것이 좋습니다. 나는 피하는 경향이있다 <xsl:choose>, <xsl:call-template>, 그리고 <xsl:with-param> 언제든지 가능할 때. 우선, 템플릿 규칙은 XSLT의 추악하고 장황한 부분을 피하는 데 도움이 될 수 있습니다.

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1">
  <StructureA xmlns="http://...">
    ...
  </StructureA>
</xsl:template>

<xsl:template match="/databean">
  <StructureB xmlns="http://...">
    ...
  </StructureB>
</xsl:template>

계속 사용하더라도 <xsl:call-template>, 당신은 그것을 통과 할 필요가 없습니다 $structure 파라미터는 현재 노드가 호출 된 템플릿에서 변경되지 않은 상태로 유지됩니다. 액세스 할 수 있습니다 //databean (또는 /databean, 나는 당신이 의미하는 바가) 당신의 어느 쪽에서나 쉽게 StructureA 또는 StructureB 현재 노드는 여전히 "/"(문서 노드)이기 때문에 템플릿.

XSLT의 핵심 처리 모델과 가장 강력한 기능 (템플릿 규칙)에 대해 더 많이 배우는 데 관심이 있으시면 체크 아웃을 권장합니다. "XSLT가 작동하는 방법", 내 무료 샘플 장 XSLT 1.0 포켓 참조.

나는 이것이 당신이 협상 한 것보다 더 많은 경우에도 당신에게 도움이 되었기를 바랍니다!

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