【问题标题】:xslt transformation to copy from xml to xml specific nodes omlyxslt 转换仅从 xml 复制到 xml 特定节点
【发布时间】:2017-07-05 03:50:34
【问题描述】:

我需要创建一些 xml 文件的子 xml。 我有一个所需节点的列表。 xslt 转换应该是什么样子? 例如输入文件:

<?xml version="1.0"?>
<root>
  <a id="A">
    <aa>text</aa>
    <bb>text</bb>
    <cc id="1">
      <aaa>text</aaa>
      <bbb>text</bbb>
    </cc>
  </a>
  <a id="B">
    <aa>text2</aa>
    <bb>text2</bb>
    <cc id="2">
      <aaa>text2</aaa>
      <bbb>text2</bbb>      
    </cc>
  </a>
</root>

想要的输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <a id="A">
      <bb>text</bb>
      <cc>
         <bbb>text</bbb>
      </cc>
   </a>
   <a id="B">
      <bb>text2</bb>
      <cc>
         <bbb>text2</bbb>
      </cc>
   </a>
</root>

目前我使用 follwonf xslt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output indent="yes"/>

  <xsl:template match="node()|@*"/>

  <xsl:template match="
 root
|root/a
|root/a/@id
|root/a/bb
|root/a/bb/node()
|root/a/cc
|root/a/cc/bbb
|root/a/cc/bbb/node()
 ">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

但我想要一个更短的列表:

 root/a/@id
|root/a/bb/node()
|root/a/cc/bbb/node()

那么如何为该短名单创建 xslt 转换?

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    嗯,在 XSLT 2.0 中,您可以对这些节点使用一个变量,在另一个变量中计算祖先,然后按如下方式使用这些变量:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
    
        <xsl:output indent="yes"/>
    
        <xsl:variable name="copy"
            select="
            root/a/@id
            |root/a/bb/node()
            |root/a/cc/bbb/node()"/>
    
        <xsl:variable name="subtrees" select="$copy/ancestor-or-self::node()"/>
    
        <xsl:template match="*[. intersect $subtrees]">
            <xsl:copy>
                <xsl:copy-of select="@*[. intersect $copy]"/>               
                <xsl:apply-templates select="node()[. intersect $subtrees]"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

    在 XSLT 3.0 中使用 static parametershadow attribute 你甚至可以进一步参数化它:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:math="http://www.w3.org/2005/xpath-functions/math"
        exclude-result-prefixes="xs math"
        version="3.0">
    
        <xsl:param name="paths" static="yes" as="xs:string"
            select="'root/a/@id | root/a/bb/node() | root/a/cc/bbb/node()'"/>
    
        <xsl:output indent="yes"/>
    
        <xsl:variable name="copy" _select="{$paths}"/>
    
        <xsl:variable name="subtrees" select="$copy/ancestor-or-self::node()"/>
    
        <xsl:template match="*[. intersect $subtrees]">
            <xsl:copy>
                <xsl:copy-of select="@*[. intersect $copy]"/>               
                <xsl:apply-templates select="node()[. intersect $subtrees]"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 谢谢!正是我需要的。我不知道这种魔法是如何起作用的,但它起作用了,而且它现在对我来说很重要!
    【解决方案2】:

    我会更具体:

    XSLT

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="a">
        <xsl:copy>
            <xsl:apply-templates select="@id|bb|cc"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="cc">
        <xsl:copy>
            <xsl:apply-templates select="bbb"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

      【解决方案3】:

      在 XSLT 1.0 中,我建议进行以下转换:

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:template match="@*|node()">
          <xsl:if test="not(. = following-sibling::*)">
            <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
          </xsl:if>
        </xsl:template>
      </xsl:stylesheet>
      

      它选择每个具有相同值的最后一个节点。

      【讨论】:

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