XSLT 2.0基于外部xml文件修改元素值

时间:2012-08-09 18:38:09

标签: xml xslt-2.0 xpath-2.0

我正在尝试通过将它们与外部文件中的elements属性相匹配来替换/修改XML文档中的某些文本节点。

这是我的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>

请注意,在外部文档中,目标元素的名称是大写的,我无法控制它,我需要在完整的xpath中使用contains到root,因为像“LEVEL_1 / ITEM_3”这样的东西”

这个解决方案正在运行,但它有点麻烦,我认为必须有一个更好的解决方案,我无法设计......

非常欢迎任何改进此建议或提示!

Thxs 明经

1 个答案:

答案 0 :(得分:0)

这可能更简单

<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>

在提供的XML文档上应用此转换时:

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

产生了想要的正确结果:

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