【问题标题】:Move/Copy node to multiple child nodes with XSLT使用 XSLT 将节点移动/复制到多个子节点
【发布时间】:2010-12-01 09:41:47
【问题描述】:

我对 XSLT 完全陌生,需要一些帮助来解决我的一个问题。我想要完成的是:

我有一个看起来像这样的文件:

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

我想保留当前文件,除了我想将国家节点复制到主节点中。所以它看起来像这样:

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

实现这一目标的最佳方法是什么?我是否需要先复制整个文件,然后再复制各个国家/地区,还是可以以某种方式一次性完成?

【问题讨论】:

    标签: xml xslt copy


    【解决方案1】:

    诀窍是使用identity template 复制整个文档,但仍然可以修改您想要的部分:

    使用此(稍作修改)输入:

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

    输入 XML 更改的说明: 提供的输入 XML 无效,因为您对每个属性都使用了双引号。此外,fun 前缀没有为 Document 节点声明。我已将 fun 前缀更改为 fun1 并将前缀绑定在根级别。


    还有这个样式表:

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

    会给你一个相同的文件,但将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>
    

    【讨论】:

    • 感谢您提供快速、优质和详细的回答!解决了一切。非常感谢!
    • 很抱歉,但只能为您的答案投票一次,如果可以的话,我会做得更多! :D
    • 所有双引号的原因是我的错,因为我只是从我的测试中复制。因为我把他们都排除在外了。但是,我注意到一件事,它现在在使用它时不会复制属性。据我所知和可以理解它应该,不是吗?或者您可以在副本中指定您不想要这些属性还是您想要?
    • 它会复制除默认命名空间声明 xmlns="" 之外的所有属性。由于它所说的只是未声明默认命名空间,并且由于这是默认行为,因此不需要每个节点上的 xmlns=""。如果您将Transaction 上的默认命名空间声明为除空字符串(例如xmlns="example.com")之外的任何其他内容,则转换将自动将空的默认命名空间声明添加到具有空默认命名空间的所有后代。
    • 酷,我明白了! :) 谢谢!
    【解决方案2】:

    只是为了好玩,最短的样式表:

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

    其他更短的不改变身份规则:

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

    注意:两者都不是xsl:copy-of,而是xsl:apply-templates。这允许进一步处理。

    【讨论】:

    • 酷。我会尝试一下,因为我已经实现了 @Per T 的版本。谢谢! :)
    【解决方案3】:

    如果您使用 xslt 生成新的 xml 文档,我将只创建该文档,然后为主节点执行此操作

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

    可能有更简单的方法来实现相同的结果..?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多