2012-08-09 4 views
1

XML 문서의 일부 텍스트 노드를 외부 파일의 요소 특성과 일치시켜 바꾸거나 수정하려고합니다. 내 XML 파일의XSLT 2.0 외부 xml 파일을 기반으로 요소 값 수정

:

<root> 
    <level_1> 
     <item_1>xxxxx</item_1> 
     <item_2>yyyyy</item_2> 
     <item_3>zzzzz</item_3> 
    </level_1> 
</root> 

XSLT 코드 :

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:functx="http://www.functx.com"> 
    <xsl:param name="additionalInfoPath"/> 
    <xsl:output indent="yes" /> 
    <xsl:function name="functx:contains-any-of" as="xs:boolean" 
       xmlns:functx="http://www.functx.com" > 
    <xsl:param name="arg" as="xs:string?"/> 
    <xsl:param name="searchStrings" as="xs:string*"/> 

    <xsl:sequence select=" 
    some $searchString in $searchStrings 
    satisfies contains($arg,$searchString) 
"/> 
</xsl:function> 
    <xsl:variable name="additionalInfo" select="doc($additionalInfoPath)"/> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="*[functx:contains-any-of(string-join(ancestor-or-self::*/upper-case(local-name()),'/'),$additionalInfo//AdditionalInfoData[@Type='ExtraInfo']/InfoDataValue/@TargetElement)]/text()"> 
       <xsl:value-of select="$additionalInfo//AdditionalInfoData[@Type='ExtraInfo']/InfoDataValue[contains(string-join(current()/ancestor-or-self::*/upper-case(local-name()),'/'),@TargetElement)]/text()"/> 
    </xsl:template> 
</xsl:stylesheet> 

및 교체를 위해에 값을 제공하는 외부 XML 문서 :

<AdditionalInfoRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <AdditionalInfoData Type="ExtraInfo"> 
    <InfoDataValue Name="ITEM_1" TargetElement="ITEM_1" TargetElementValue="">111111</InfoDataValue> 
    <InfoDataValue Name="LEVEL_1$ITEM_3" TargetElement="LEVEL_1/ITEM_3" TargetElementValue="">333333</InfoDataValue> 
    </AdditionalInfoData> 
</AdditionalInfoRoot> 

참고하는 외부에서 목표 요소의 이름을 대문자로 문서화하고 문서를 제어 할 필요가 없습니다. "LEVEL_1/ITEM_3"과 같은 이유로 루트에 대한 전체 xpath에서 contains를 사용합니다.

이 솔루션은 작동하지만 어떻게 든 성가신 그리고 내가 고안 할 수 아니에요 더 나은 솔루션이 있어야합니다 생각 ...

어떤 제안을하거나 매우 환영 개선하기 위해 힌트!

Thxs Vlax

+0

변환의 결과는 무엇입니까? 제발, 질문을 수정하고 이것을 제공하십시오. –

+0

@Dimitre : 답장을 보내 주셔서 감사합니다. 답변이 늦어서 죄송합니다. – Vlax

+0

Vlax, 여러분 안녕하세요. –

답변

0

이 간단 수 있습니다 :

<root> 
    <level_1> 
     <item_1>xxxxx</item_1> 
     <item_2>yyyyy</item_2> 
     <item_3>zzzzz</item_3> 
    </level_1> 
</root> 

원하는, 올바른 :이 변환이 제공된 XML 문서에 적용되는

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

<xsl:variable name="vLookupDoc"> 
    <t> 
    <e path="ITEM_1">111111</e> 
    <e path="LEVEL_1/ITEM_3">333333</e> 
    </t> 
</xsl:variable> 

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

<xsl:template match="text()"> 
    <xsl:variable name="vRep" select= 
    "$vLookupDoc/*/e 
     [ends-with(
     string-join(current()/ancestor::*[parent::*]/lower-case(name(.)), '/'), 
     lower-case(@path) 
       ) 
     ] 
     /string(.) 
    "/> 

    <xsl:sequence select="(., $vRep)[last()]"></xsl:sequence> 
</xsl:template> 
</xsl:stylesheet> 

결과가 생성됩니다.

<root> 
     <level_1> 
      <item_1>111111</item_1> 
      <item_2>yyyyy</item_2> 
      <item_3>333333</item_3> 
     </level_1> 
</root>