简体   繁体   English

使用XSLT将节点移动/复制到多个子节点

[英]Move/Copy node to multiple child nodes with XSLT

I'm completely new to XSLT and need some help to solve one of my issues. 我是XSLT的新手,需要一些帮助来解决我的问题之一。 What I want to accomplish is this: 我要完成的是:

I have a file looking something like this: 我有一个看起来像这样的文件:

<Transaction>
    <Date>2010-10-14T12:06:12.164+01:00</Date>
    <Production>NO</Production>
    <Document fun:OID="1.9.101106">
        <DocumentType xmlns="">Monthly A</DocumentType>
        <RangeName xmlns="">Range Name</RangeName>
        <Name xmlns="">Equity</Name>
        <Language xmlns="">English</Language>
        <Class xmlns="">A Acc</Class>
        <Active xmlns="">YES</Active>
        <Country xmlns="">UK</Country>
        <Country xmlns="">Luxembourg</Country>
        <Country xmlns="">Denmark</Country>
        <Country xmlns="">Malta</Country>
        <Primary fun1:OID="1.9.101106" xmlns="" xmlns:fun1="DocumentXML.com">
              <Name>SISF-Indian-Equity-A-Acc-FMR-UKEN</Name>
              <FileSizeInKB>176784</FileSizeInKB>
              <FileType>pdf</FileType>
              <ReportingPeriod>September</ReportingPeriod>
              <ReportingYear>2010</ReportingYear>
        </Primary>
        <Primary fun1:OID="1.9.101118" xmlns="" xmlns:fun1="DocumentXML.com">
              <Name>SISF-Indian-Equity-A-Acc</Name>
              <FileSizeInKB>176784</FileSizeInKB>
              <FileType>pdf</FileType>
              <ReportingPeriod>September</ReportingPeriod>
              <ReportingYear>2010</ReportingYear>
        </Primary>
    </Document>
</Transaction>

And I want to keep the current file, except that I want to copy the country nodes in to be in the Primary node. 我想保留当前文件,除了要复制国家(地区)节点到“主要”节点中。 So it would look something like this: 所以看起来像这样:

<Transaction>
    <Date>2010-10-14T12:06:12.164+01:00</Date>
    <Production>NO</Production>
    <Document fun:OID="1.9.101106">
        <DocumentType xmlns="">Monthly A</DocumentType>
        <RangeName xmlns="">Range Name</RangeName>
        <Name xmlns="">Equity</Name>
        <Language xmlns="">English</Language>
        <Class xmlns="">A Acc</Class>
        <Active xmlns="">YES</Active>
        <Country xmlns="">UK</Country>
        <Country xmlns="">Luxembourg</Country>
        <Country xmlns="">Denmark</Country>
        <Country xmlns="">Malta</Country>
        <Primary fun1:OID="1.9.101106" xmlns="" xmlns:fun1="DocumentXML.com">
              <Name>SISF-Indian-Equity-A-Acc-FMR-UKEN</Name>
              <FileSizeInKB>176784</FileSizeInKB>
              <FileType>pdf</FileType>
              <ReportingPeriod>September</ReportingPeriod>
              <ReportingYear>2010</ReportingYear>
              <Country xmlns="">UK</Country>
              <Country xmlns="">Luxembourg</Country>
              <Country xmlns="">Denmark</Country>
              <Country xmlns="">Malta</Country>
        </Primary>
        <Primary fun1:OID="1.9.101118" xmlns="" xmlns:fun1="DocumentXML.com">
              <Name>SISF-Indian-Equity-A-Acc</Name>
              <FileSizeInKB>176784</FileSizeInKB>
              <FileType>pdf</FileType>
              <ReportingPeriod>September</ReportingPeriod>
              <ReportingYear>2010</ReportingYear>
              <Country xmlns="">UK</Country>
              <Country xmlns="">Luxembourg</Country>
              <Country xmlns="">Denmark</Country>
              <Country xmlns="">Malta</Country>
        </Primary>
    </Document>
</Transaction>

What would the best approach be to accomplish that? 最好的方法是实现这一目标? Do I need to do a copy of the whole document first and then copy the individual countries, or can I do this in one go somehow? 我需要先制作整个文档的副本,然后再复制各个国家/地区,还是可以一次性完成?

The trick is to use an identity template to copy the whole document but still be able to modify the parts you want: 诀窍是使用身份模板复制整个文档,但仍然能够修改所需的部分:

With this (slightly modified) input: 使用此(略作修改)输入:

<?xml version="1.0" encoding="UTF-8"?>
<Transaction xmlns:fun1="DocumentXML.com">
  <Date>2010-10-14T12:06:12.164+01:00</Date>
  <Production>NO</Production>
  <Document fun1:OID="1.9.101106">
    <DocumentType xmlns="">Monthly A</DocumentType>
    <RangeName xmlns="">Range Name</RangeName>
    <Name xmlns="">Equity</Name>
    <Language xmlns="">English</Language>
    <Class xmlns="">A Acc</Class>
    <Active xmlns="">YES</Active>
    <Country xmlns="">UK</Country>
    <Country xmlns="">Luxembourg</Country>
    <Country xmlns="">Denmark</Country>
    <Country xmlns="">Malta</Country>
    <Primary fun1:OID="1.9.101106" xmlns="" xmlns:fun1="DocumentXML.com">
      <Name>SISF-Indian-Equity-A-Acc-FMR-UKEN</Name>
      <FileSizeInKB>176784</FileSizeInKB>
      <FileType>pdf</FileType>
      <ReportingPeriod>September</ReportingPeriod>
      <ReportingYear>2010</ReportingYear>
    </Primary>
    <Primary fun1:OID="1.9.101118" xmlns="" xmlns:fun1="DocumentXML.com">
      <Name>SISF-Indian-Equity-A-Acc</Name>
      <FileSizeInKB>176784</FileSizeInKB>
      <FileType>pdf</FileType>
      <ReportingPeriod>September</ReportingPeriod>
      <ReportingYear>2010</ReportingYear>
    </Primary>
  </Document>
</Transaction>

Explanation for the changes in input XML: The supplied input XML isn't valid because you use double quotes for every attribute. 输入XML更改的说明:提供的输入XML无效,因为您对每个属性都使用了双引号。 Also, the fun prefix isn't declared for the Document node. 另外,未为Document节点声明fun前缀。 I've changed the fun prefix to fun1 and bound the prefix at root level. 我已将fun前缀更改为fun1并在根级别绑定了该前缀。


And this stylesheet: 这个样式表:

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

  <xsl:output indent="yes"/>

  <!-- This identity template copies the document -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!-- This template will only match the 'Primary' nodes
       and modify them the way you want. -->
  <xsl:template match="Primary">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
      <!-- As you can see, this is the only difference
           between the identity template and this specific
           template. -->
      <xsl:copy-of select="../Country"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Will give you an identical document but with Country copied into Primary : 将给您相同的文件,但将Country复制到Primary

<?xml version="1.0" encoding="UTF-8"?>
<Transaction xmlns:fun1="DocumentXML.com">
  <Date>2010-10-14T12:06:12.164+01:00</Date>
  <Production>NO</Production>
  <Document fun1:OID="1.9.101106">
      <DocumentType>Monthly A</DocumentType>
      <RangeName>Range Name</RangeName>
      <Name>Equity</Name>
      <Language>English</Language>
      <Class>A Acc</Class>
      <Active>YES</Active>
      <Country>UK</Country>
      <Country>Luxembourg</Country>
      <Country>Denmark</Country>
      <Country>Malta</Country>
      <Primary fun1:OID="1.9.101106">
         <Name>SISF-Indian-Equity-A-Acc-FMR-UKEN</Name>
         <FileSizeInKB>176784</FileSizeInKB>
         <FileType>pdf</FileType>
         <ReportingPeriod>September</ReportingPeriod>
         <ReportingYear>2010</ReportingYear>
         <Country>UK</Country>
         <Country>Luxembourg</Country>
         <Country>Denmark</Country>
         <Country>Malta</Country>
      </Primary>
      <Primary fun1:OID="1.9.101118">
         <Name>SISF-Indian-Equity-A-Acc</Name>
         <FileSizeInKB>176784</FileSizeInKB>
         <FileType>pdf</FileType>
         <ReportingPeriod>September</ReportingPeriod>
         <ReportingYear>2010</ReportingYear>
         <Country>UK</Country>
         <Country>Luxembourg</Country>
         <Country>Denmark</Country>
         <Country>Malta</Country>
      </Primary>
  </Document>
</Transaction>

Just for fun, the shortest stylesheet: 只是为了好玩,最短的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <xsl:apply-templates select="self::Primary/../Country"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Other shorter without changing the identity rule: 其他较短但未更改身份规则:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Primary/*[last()]">
        <xsl:call-template name="identity"/>
        <xsl:apply-templates select="../../Country"/>
    </xsl:template>
</xsl:stylesheet>

Note : Both don't use xsl:copy-of but xsl:apply-templates . 注意 :两者都不使用xsl:copy-of但是使用xsl:apply-templates This allows further processing. 这允许进一步处理。

well if you are using xslt to generate a new xml doccument i would just create the doccument then for the primary node do this 好吧,如果您使用xslt生成一个新的xml文档,我将只创建该文档,然后为主节点执行此操作

<xsl:for-each select="../Country">
<Country><xsl:value-of select="."/></Country>
</xsl:for-each>

there may be simpler ways to achieve the same results..? 可能会有更简单的方法来达到相同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM