0

我有几个 XML 文件,如下所示:

文件:1.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <config>
       <info>
           <info1>val1</info1>
           <info2>val2</info2>
       </info>
       <info>
           <info1>val3</info1>
           <info2>val4</info2>
       </info>
   </config>

文件:2.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <config>
       <info>
           <info1>val5</info1>
           <info2>val6</info2>
       </info>
       <info>
           <info1>val7</info1>
           <info2>val8</info2>
       </info>
   </config>

文件:3.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <config>
       <info>
           <info1>val9</info1>
           <info2>val10</info2>
       </info>
       <info>
           <info1>val11</info1>
           <info2>val12</info2>
       </info>
   </config>

使用 XSLT2.0 (saxon),我想合并它们并添加到每个节点:

<info3>XXX</info3>

并且

<file>filename.xml</file>

filename.xml 是从中复制信息的文件。

输出应如下所示:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <config>
       <info>
           <info1>val1</info1>
           <info2>val2</info2>
           <info3>XXX</info3>
           <file>1.xml</file>
       </info>
       <info>
           <info1>val3</info1>
           <info2>val4</info2>
           <info3>XXX</info3>
           <file>1.xml</file>
       </info>
       <info>
           <info1>val5</info1>
           <info2>val6</info2>
           <info3>XXX</info3>
           <file>2.xml</file>
       </info>
       <info>
           <info1>val7</info1>
           <info2>val8</info2>
           <info3>XXX</info3>
           <file>2.xml</file>
       </info>
       <info>
           <info1>val9</info1>
           <info2>val10</info2>
           <info3>XXX</info3>
           <file>3.xml</file>
       </info>
       <info>
           <info1>val11</info1>
           <info2>val12</info2>
           <info3>XXX</info3>
           <file>3.xml</file>
       </info>
   </config>

到目前为止,我已经能够通过创建一个 XML 文件来合并文件,该文件列出了我要合并的文件 (merge.xml):

<mergeData newRoot="config">
   <filelist>
       <fileItem>1.xml</fileItem>
       <fileItem>2.xml</fileItem>
       <fileItem>3.xml</fileItem>
   </filelist>
</mergeData>

使用以下 XSL (merge.xsl):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:param  name="new">
   <info>XXX</info>
</xsl:param>

<xsl:template match="/">
   <xsl:element name="{mergeData/@newRoot}">
      <xsl:apply-templates select="mergeData/fileList/fileItem"/>
   </xsl:element>
</xsl:template>

<xsl:template match="fileItem">
     <xsl:apply-templates select="document(translate(., '\', '/'))/config/*"/>
</xsl:template>

<xsl:template match="config/*">
   <xsl:copy>
       <xsl:copy-of select="node()"/>
       <xsl:copy-of select="$new"/>
   </xsl:copy>
   <file><xsl:value-of select="tokenize(document-uri(.), '/')[last()]"/></file>
 </xsl:template>

我应该如何修改 XSL 以同时将文件名放入每个信息中。

4

2 回答 2

0

真的,你应该做的唯一一件事就是移动filexsl:copy.

示例(与其他几个小模组):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
    <xsl:output indent="yes"/>
    <xsl:param  name="new">
        <info3>XXX</info3>
    </xsl:param>

    <xsl:template match="/">
        <xsl:element name="{mergeData/@newRoot}">
            <xsl:apply-templates select="mergeData/filelist/fileItem"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="fileItem">
        <xsl:apply-templates select="document(translate(., '\', '/'))/config/*"/>
    </xsl:template>

    <xsl:template match="config/*">
        <xsl:copy>
            <xsl:copy-of select="node(),$new"/>
            <file><xsl:value-of select="tokenize(document-uri(/), '/')[last()]"/></file>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

您也可以使用collection()而不是创建单独的mergeData.xml文件来执行此操作:

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

    <xsl:param name="newRoot" select="'config'"/>
    <xsl:param name="new">
        <info3>XXX</info3>
    </xsl:param>

    <xsl:template match="/">
        <xsl:element name="{$newRoot}">
            <xsl:apply-templates select="collection('file:///C:/some/path?select=[0-9]*.xml')/*/info"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="info">
        <xsl:copy>
            <xsl:copy-of select="@*|node(),$new"/>
            <file><xsl:value-of select="tokenize(document-uri(/),'/')[last()]"/></file>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

由于您使用的是 Saxon,因此另一种选择是saxon:discard-document()与您的mergeData.xml输入一起使用。如果您在 中列出了很多文件mergeData.xml,这有助于减少内存消耗。(它确实需要 Saxon PE 或 EE 或允许扩展功能的旧版 Saxon。)

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

  <xsl:param name="new">
    <info3>XXX</info3>
  </xsl:param>

  <xsl:template match="/mergeData">
    <xsl:element name="{@newRoot}">
      <xsl:apply-templates select="filelist/fileItem"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="fileItem">
    <xsl:apply-templates select="document(.)/saxon:discard-document(.)/*/*" xmlns:saxon="http://saxon.sf.net/"/>          
  </xsl:template>

  <xsl:template match="info">
    <xsl:copy>
      <xsl:copy-of select="@*|node(),$new"/>
      <file><xsl:value-of select="tokenize(document-uri(/),'/')[last()]"/></file>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
于 2013-10-24T22:32:16.787 回答
0

以下 XSLT 产生您需要的结果:

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

  <xsl:output method="xml" encoding="UTF-8"/>

  <xsl:param  name="new">
    <info>XXX</info>
  </xsl:param>

  <xsl:template match="/mergeData">
    <config>

    <xsl:for-each select="filelist/fileItem">
      <xsl:variable name="filename" select="text()"/>

      <xsl:for-each select="document($filename)/config/info">
        <info>
          <xsl:copy-of select="./*"/>
          <xsl:element name="info{count(*)+1}">
            <xsl:value-of select="$new"/>
          </xsl:element>
          <file><xsl:value-of select="$filename"/></file>
        </info>

      </xsl:for-each>
    </xsl:for-each>

    </config>
  </xsl:template>

</xsl:stylesheet>

笔记:

  • 这已经适用于 XSLT 1.0,因此我更改了 XSLT 声明。
  • 由于这种方法是自上而下的,具有预定义的子结构,因此不再使用newRoot输入文件的属性。
  • 答案不会提取输入文件的基本名称,而是使用合并配置中提供的完整路径。您可能想要恢复这种简化。当然,使用tokenize会将其推回到 XSLT 2.0 或扩展功能。
于 2013-10-24T20:22:11.477 回答