1

我正在尝试通过将 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>

请注意,在外部文档中,目标元素的名称是大写的,我无法控制它,并且由于“LEVEL_1/ITEM_3”之类的原因,我需要在根的完整 xpath 中使用 contains。

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

非常欢迎任何改进这一点的建议或提示!

感谢 Vlax

4

1 回答 1

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>
于 2012-08-11T16:09:44.887 回答