将文件名信息收集到XML节点中

时间:2013-10-16 17:08:45

标签: xslt xslt-2.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以同时获取每个信息的文件名。

2 个答案:

答案 0 :(得分: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或扩展函数。

答案 1 :(得分:0)

您唯一应该做的就是在file内移动xsl:copy

示例(带有其他一些小mod):

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