从参数迭代插入值

时间:2020-07-20 11:50:16

标签: xml xslt

我有大约10个要在XML文档上应用的参数(键-值对)列表。

每当找到TESTWORD作为值时,请使用以下键并将其替换为适当的值。还要替换该节点的名称。

输入:

<Company>
   <Employee>
      <FirstName>Homer</FirstName>
      <LastName>Simpson</LastName>
      <ContactNo>1234567890</ContactNo>
      <Address>
         <City>Springfield</City>
         <Note>TESTWORD key1</Note> <!-- change this -->
      </Address>
   </Employee>
   <Employee>
      <FirstName>Peter</FirstName>
      <LastName>Griffin</LastName>
      <ContactNo>0987654321</ContactNo>
      <Address>
         <City>Quahog</City>
         <Note>TESTWORD key2</Note> <!-- change this -->
      </Address>
   </Employee>
</Company>

预期输出:

<Company>
   <Employee>
      <FirstName>Homer</FirstName>
      <LastName>Simpson</LastName>
      <ContactNo>1234567890</ContactNo>
      <Address>
         <City>Springfield</City>
         <NewElem>My new value</NewElem> <!-- changed -->
      </Address>
   </Employee>
   <Employee>
      <FirstName>Peter</FirstName>
      <LastName>Griffin</LastName>
      <ContactNo>0987654321</ContactNo>
      <Address>
         <City>Quahog</City>
         <NewElem>Another value</NewElem> <!-- changed -->
      </Address>
   </Employee>
</Company>

我的XSLT方法:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes" method="xml" encoding="utf-8" />

    <!-- Param list -->
    <xsl:param name="key1" select="'My new value'" />
    <xsl:param name="key2" select="'Another value'" />
    <!-- ... more params -->

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

    <xsl:template match="Note[.='TESTWORD key1']"> <!-- iterate all params -->
        <xsl:element name="NewElem">
            <xsl:value-of select="$key1" /> <!-- replace all values -->
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

第一次出现的<Note>TESTWORD key1</Note>被正确地替换为<NewElem>My new value</NewElem>。但其余事件没有。


我可以复制这部作品的x倍:

<xsl:template match="Note[.='TESTWORD keyX']">
   <xsl:element name="NewElem">
      <xsl:value-of select="$keyX" />
   </xsl:element>
</xsl:template>

但是也许有一种迭代方法?


PS:我正在使用 Java

1 个答案:

答案 0 :(得分:1)

在Saxon 9.8和更高版本中,您可以声明XSLT 3 / XPath 3.1类型为map(xs:string, xs:string)的参数(即具有字符串键和值的映射)来表示键/值对。然后,您可以处理它们并以匹配模式使用它们:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="#all"
    version="3.0">
    
  <xsl:param name="map"
             as="map(xs:string, xs:string)"
             select="map { 
                        'key1' : 'My new value',
                        'key2' : 'Another value' 
                    }"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:variable name="map-keys" select="map:keys($map)"/>
  
  <xsl:template match="Note[some $key in $map-keys satisfies . = 'TESTWORD ' || $key]">
      <NewElemen>
          <xsl:value-of select="$map($map-keys[current() = 'TESTWORD ' || .])"/>
      </NewElemen>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pNmCzsU

从Java中,有一些方法可以从类似的Java集合中构造这样的XdmMap,例如makeMaphttp://saxonica.com/html/documentation9.9/javadoc/net/sf/saxon/s9api/XdmMap.html#makeMap-java.util.Map-)将java.util.Map转换为XdmMap。

建议将s9api和Xslt30Transformer与Saxon 9.8或更高版本一起使用以运行XSLT 3,然后可以在带有http://saxonica.com/html/documentation9.9/javadoc/net/sf/saxon/s9api/Xslt30Transformer.html#setStylesheetParameters-java.util.Map-的类实例上设置参数。

但是,如果Saxon在类路径上,您还可以使用JAXP XdmMap来传递Transformer

    Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource("map-test1.xsl"));
    
    Map<String, String> map1 = new HashMap<>();
    map1.put("key2", "value passed in from JAXP API");
    
    transformer.setParameter("map", XdmMap.makeMap(map1));
    
    transformer.transform(new StreamSource("input-sample1.xml"), new StreamResult(System.out));