XSLT:确保存在具有默认内容的某些元素

| 我需要确保XML文档始终包含以下节点:
<group>
    <section>0001</section>
    <head>0002</head>
    <body>0003</body>
</group>
典型的XML输入文件如下所示(组节点应始终位于类别和摘要之前):
<story>
    <group>
        <section>section-content</section>
        <head>head-content</head>
        <body>body-content</body>
        <extra>extra-content</extra>
    </group>
    <category>some text</category>
    <summary>some text</summary>
</story>
但是不能保证group元素或其任何子元素将存在。 因此,给出一个XML文档:
<story>
    <category>some text</category>
    <summary>some text</summary>
</story>
输出应如下所示:
<story>
    <group>
        <section>0001</section>
        <head>0002</head>
        <body>0003</body>
    </group>
    <category>some text</category>
    <summary>some text</summary>
</story>
XSLT不应修改现有内容,例如。
<story>
    <group>
        <section>existing text</section>
        <extra>existing text</extra>
    </group>
    <category>some text</category>
    <summary>some text</summary>
</story>
应转换为:
<story>
    <group>
        <section>existing text</section>
        <head>0002</head>
        <body>0003</body>
        <extra>existing text</extra>
    </group>
    <category>some text</category>
    <summary>some text</summary>
</story>
以Tomalak的答案为基础,我想到了这一点:
<xsl:stylesheet   version=\"1.0\"
  xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"
  xmlns:subst=\"http://tempuri.com/mysubst\"
>

<xsl:strip-space elements=\"*\"/>
<xsl:output method=\"xml\" encoding=\"utf-8\" indent=\"yes\"/>

  <!-- These defaults (elements and contents) can be modified at any time -->
  <subst:defaults>
    <subst:element name=\"group\">
    <subst:section>0001</subst:section>
    <subst:head>0002</subst:head>
    <subst:body>0002</subst:body>
    </subst:element>
  </subst:defaults>

<!-- this makes the above available as a variable -->
<xsl:variable name=\"defaults\" select=\"document(\'\')/*/subst:defaults\" />

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

<xsl:template match=\"story[not(group)]\">
  <xsl:copy>
   <xsl:apply-templates select=\"@*\"/>
      <xsl:element name=\"group\"></xsl:element>
   <xsl:apply-templates select=\"node()\"/>
  </xsl:copy>
 </xsl:template>

  <xsl:template match=\"group\">
    <xsl:copy>
      <xsl:copy-of select=\"@*|*\"/>
      <xsl:call-template name=\"create-defaults\" />
    </xsl:copy>
  </xsl:template>

  <!-- Insert the defaults-->
  <xsl:template name=\"create-defaults\">
    <xsl:variable name=\"this\" select=\".\" />
    <xsl:for-each select=\"$defaults/subst:element[@name = name($this)]/*\">
      <xsl:if test=\"not($this/*[name() = local-name(current())])\">
        <xsl:apply-templates select=\".\" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

<!-- Remove the namespaces -->
  <xsl:template match=\"*\">
    <xsl:element name=\"{local-name()}\">
      <xsl:apply-templates select=\"@*|node()\"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
如果group元素已经存在,这似乎可行,但是如果group元素不存在,我想不通如何使它工作。     
已邀请:
        此XSLT 1.0转换
<xsl:stylesheet   version=\"1.0\"
  xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"
  xmlns:subst=\"http://tempuri.com/mysubst\"
  exclude-result-prefixes=\"subst\"
>
  <xsl:strip-space elements=\"*\"/>
  <xsl:output method=\"xml\" encoding=\"utf-8\" indent=\"yes\"/>

  <subst:defaults>
    <subst:element name=\"group\">
      <subst:element name=\"section\">0001</subst:element>
      <subst:element name=\"head\">0002</subst:element>
      <subst:element name=\"body\">0003</subst:element>
    </subst:element>
  </subst:defaults>

  <xsl:variable name=\"subst\" select=\"document(\'\')/*/subst:defaults/subst:element\" />

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

  <!-- subst:element outputs a new element with the given @name -->
  <xsl:template match=\"subst:element\">
    <xsl:element name=\"{@name}\">
      <!-- this would also copy any additional \"default\" attribute! -->
      <xsl:apply-templates select=\"@*[not(name() = \'name\')] | node()\"/>
    </xsl:element>
  </xsl:template>

  <!-- only stories without any group get \"special\" treatment -->
  <xsl:template match=\"story[not(group)]\">
    <xsl:copy>
      <xsl:apply-templates select=\"@*\" />
      <xsl:apply-templates select=\"$subst[@name = \'group\']\" mode=\"copy-or-default\" />
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <!-- a group first outputs all \"default\" children, then any extra children -->    
  <xsl:template match=\"group\">
    <xsl:variable name=\"defaults\" select=\"$subst[@name = \'group\']/*\" />
    <xsl:copy>
      <xsl:apply-templates select=\"@*\" />
      <xsl:apply-templates select=\"$defaults\" mode=\"copy-or-default\">
        <xsl:with-param name=\"parent\" select=\".\" />
      </xsl:apply-templates>
      <!-- any elements that don\'t have a default AND any non-element children -->
      <xsl:apply-templates select=\"
        *[not(name() = $defaults/@name)] | node()[not(self::*)]
      \" />
    </xsl:copy>
  </xsl:template>

  <!-- in \"copy-or-default\" mode, this checks the context parent
       and either copies the element from there or uses the default --> 
  <xsl:template match=\"subst:element\" mode=\"copy-or-default\">
    <xsl:param name=\"parent\" />

    <xsl:choose>
      <xsl:when test=\"$parent and $parent/*[name() = current()/@name]\">
        <xsl:apply-templates select=\"$parent/*[name() = current()/@name]\" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select=\".\" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>
应用于此输入时
<x>
  <story>
    <group>
      <section>0001</section>
      <head>0002</head>
      <body>0003</body>
    </group>
    <category>some text</category>
    <summary>some text</summary>
  </story>
  <story>
    <group>
      <body>0004</body>
      <!-- a comment! -->
      <foo>blah</foo>
    </group>
    <category>some text</category>
    <summary>some text</summary>
  </story>
  <story>
    <category>some text</category>
    <summary>some text</summary>
  </story>
</x>
产生:
<x>
  <story>
    <group>
      <section>0001</section>
      <head>0002</head>
      <body>0003</body>
    </group>
    <category>some text</category>
    <summary>some text</summary>
  </story>
  <story>
    <group>
      <section>0001</section>
      <head>0002</head>
      <body>0004</body>
      <!-- a comment! -->
      <foo>blah</foo>
    </group>
    <category>some text</category>
    <summary>some text</summary>
  </story>
  <story>
    <group>
      <section>0001</section>
      <head>0002</head>
      <body>0003</body>
    </group>
    <category>some text</category>
    <summary>some text</summary>
  </story>
</x>
    

要回复问题请先登录注册