Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT复制全部并根据条件替换_Xml_Xslt - Fatal编程技术网

Xml XSLT复制全部并根据条件替换

Xml XSLT复制全部并根据条件替换,xml,xslt,Xml,Xslt,我需要一个XSLT转换,将整个输入文档复制到输出文档,如果输入文档不包含某个元素,则插入一个具有默认值的特定元素 具体来说,我想转换这种通用形式的输入XML <Begin> <tag1>a</tag1> <tag2>b</tag2> </Begin> 到 x C 这是我当前的XSLT: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.

我需要一个XSLT转换,将整个输入文档复制到输出文档,如果输入文档不包含某个元素,则插入一个具有默认值的特定元素

具体来说,我想转换这种通用形式的输入XML

<Begin>
    <tag1>a</tag1>
    <tag2>b</tag2>
</Begin>


x
C
这是我当前的XSLT:

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

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>


它复制整个输入文档,但不提供默认的
元素。我不能在该样式表中的模板内使用
,因为它将在没有
的元素中插入
,并且我不能在模板后放置
choose
,因为它无效。如何仅为
元素提供默认的
元素?

如果没有
tag1
并插入
tag1
,则可以添加与
Begin
匹配的模板。这里请注意,这适用于非常简单的示例,但是如果您有一个更复杂的案例,需要插入大量元素或多个元素,那么解决方案可能会变得更复杂

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

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Begin[not(tag1)]">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <tag1>x</tag1>
      <xsl:apply-templates select="node()" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

x

如果没有
tag1
,则可以添加与
Begin
匹配的模板,并插入
tag1
。这里请注意,这适用于非常简单的示例,但是如果您有一个更复杂的案例,需要插入大量元素或多个元素,那么解决方案可能会变得更复杂

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

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Begin[not(tag1)]">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <tag1>x</tag1>
      <xsl:apply-templates select="node()" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

x

您不能将
元素放在模板之外,这是正确的。XSL通过转换输入文档的节点进行操作;您只能根据特定节点的转换方式(即通过模板)来表达转换的细节

此外,通过提供替代模板或
select
表达式来表达替代方案通常比在模板内使用
等逻辑元素更为自然

在这种情况下,您需要考虑两种选择:

  • 输入文档的
    /Begin
    元素有一个子元素
    tag1
  • 输入文档的
    /Begin
    元素没有
    tag1
    子元素
  • 在第一种情况下,您不需要做任何特殊的事情——您已经编写的身份转换将做正确的事情。因此,您只需要一个适当的模板来处理后一种选择。只要它比标识转换具有更高的优先级,它将用于
    Begin
    元素,而不是标识转换,只要它适用

    比如说,

    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" indent="yes" omit-xml-declaration="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Begin[count(tag1) = 0]">
        <xsl:copy>
          <tag1>x</tag1>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    
    
    x
    

    请注意添加的模板,它(仅)适用于没有子元素的
    开始
    元素。它复制整个元素及其子节点,但也插入一个

    如果您正确,则不能将
    元素放在模板外部。XSL通过转换输入文档的节点进行操作;您只能根据特定节点的转换方式(即通过模板)来表达转换的细节

    此外,通过提供替代模板或
    select
    表达式来表达替代方案通常比在模板内使用
    等逻辑元素更为自然

    在这种情况下,您需要考虑两种选择:

  • 输入文档的
    /Begin
    元素有一个子元素
    tag1
  • 输入文档的
    /Begin
    元素没有
    tag1
    子元素
  • 在第一种情况下,您不需要做任何特殊的事情——您已经编写的身份转换将做正确的事情。因此,您只需要一个适当的模板来处理后一种选择。只要它比标识转换具有更高的优先级,它将用于
    Begin
    元素,而不是标识转换,只要它适用

    比如说,

    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" indent="yes" omit-xml-declaration="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Begin[count(tag1) = 0]">
        <xsl:copy>
          <tag1>x</tag1>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    
    
    x
    

    请注意添加的模板,它(仅)适用于没有子元素的
    开始
    元素。它复制整个元素及其子节点,但也插入一个

    ,您所描述的内容没有什么意义。为什么特别需要通过在
    应用模板
    中选择
    节点()|@*
    来执行此操作?除了是否存在
    /Begin/tag1
    之外,转换的输出是否应该依赖于其他任何东西?从源文档“复制”的转换实际上是什么?我想特别使用node()|@*进行转换,因为我在过去的两个小时里一直在尝试这样做:):P无论如何,如果您有其他方法,我也很乐意看到。不,输出不应该依赖于除是否存在/Begin/tag1之外的任何东西。我想将源中的所有元素复制到目标。所以我想node()|@*是唯一的方法?不是吗?你前后矛盾。如果要将所有元素从输入复制到输出,则输出取决于输入中的所有元素。您之前说过,这只取决于
    /Begin/tag1
    是否存在。我已经更新了问题,以反映您在评论和聊天中提供的澄清。如果我仍然误解了,那么请做出任何其他必要的改变。你所描述的毫无意义。为什么特别需要通过在
    应用模板
    中选择
    节点()|@*
    来执行此操作?除了是否存在
    /Begin/tag1
    之外,转换的输出是否应该依赖于其他任何东西?从源文档“复制”的转换实际上是什么