5

次のような xml ドキュメントがあります。

<p>
  <c1 />
  <c2 />
</p>

子要素 c1 と c2 はオプションですが、処理ステップのために存在する必要があります。そのため、空の要素として追加する xslt スタイルシートを作成しようとしています (子の順序は関係ありません)。

ここに私のスタイルシートがあります:

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

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

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

子要素の 1 つだけが欠落している限り、これは正常に機能します。ただし、両方が欠落している場合は、c1 のみが作成されます。それを防ぎ、c1 と c2 の両方 (実際には約 10 の子) を強制的に作成するにはどうすればよいですか?

ありがとう。ジョスト

4

3 に答える 3

4

xsl:ifアプローチはあまり好きではありません。ノードの順序が変わってもかまわない限り、もっと良いことがあります。

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

<!--copy rules specific to p-->
<xsl:template match="p">
    <xsl:copy>
        <xsl:apply-templates select="not(self::c1|self::c2)"/>
        <c1><xsl:apply-templates select="c1/*"/></c1>
        <c2><xsl:apply-templates select="c2/*"/></c2>
    </xsl:copy>
<xsl:template>

基本的な考え方は、c1ノードとc2ノードが存在する場合はコンテンツを使用して明示的に生成し、存在しない場合は何も生成しないことです。

于 2012-05-23T01:46:36.673 に答える
2

私はこのようにします:

<xsl:template match="p"> 
  <xsl:copy> 
    <xsl:apply-templates select="@*|node()"/> 
    <xsl:if test="not(c1)">
      <c1 /> 
    </xsl:if>
    <xsl:if test="not(c2)">
      <c2 /> 
    </xsl:if>
  </xsl:copy> 
</xsl:template> 

可能な子ノードのリストが長い場合は、それらを変数に入れて、for-each個別ではなく代わりに使用できifます。

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
  exclude-result-prefixes="msxsl">

  <xsl:output method="xml" indent="yes"/>

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

  <xsl:variable name="childrenFragment">
    <c1/>
    <c2/>
  </xsl:variable>

  <xsl:template match="p">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:variable name="this" select="."/>
      <xsl:for-each select="msxsl:node-set($childrenFragment)/*">
        <xsl:variable name="localName" select="local-name()"/>
        <xsl:if test="not($this/*[local-name()=$localName])">
          <xsl:element name="{$localName}"/>
        </xsl:if>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

必要なすべての要素をchildrenFragment変数に追加するだけです。

(これmsxsl:node-setはMicrosoft固有のものであり、別のXSLTプロセッサを使用している場合は、少し異なるものが必要になります)

于 2012-05-22T23:26:16.833 に答える
2

以下は、明示的な XSLT 条件付き命令または命令を使用しない、一般的な XSLT 1.0 ソリューション (N 個の追加要素で使用可能)xsl:elementです

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

 <xsl:variable name="vrtfNodesToAdd">
  <c1/><c2/>
</xsl:variable>

 <xsl:variable name="vNodesToAdd" select=
  "ext:node-set($vrtfNodesToAdd)/*"/>

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

 <xsl:template match="p">
   <xsl:variable name="vCurrentP" select="."/>

   <xsl:copy>
    <xsl:apply-templates/>

    <xsl:for-each select="$vNodesToAdd">
       <xsl:copy-of select=
       "self::node()[not($vCurrentP/*[name() = name(current())])]"/>
    </xsl:for-each>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

この変換が次の XML ドキュメントに適用される場合:

<t>
 <p>
 </p>
 <p>
  <c1/>
 </p>
 <p>
  <c2/>
 </p>
 <p>
  <c1/><c2/>
 </p>
</t>

必要な正しい結果が生成されます。

<t>
  <p>
    <c1 />
    <c2 />
  </p>
  <p>
    <c1 />
    <c2 />
  </p>
  <p>
    <c2 />
    <c1 />
  </p>
  <p>
    <c1 />
    <c2 />
  </p>
</t>
于 2012-05-23T03:56:35.877 に答える