English 中文(简体)
XSLT 转换以添加多个非现有儿童元素
原标题:XSLT Transformation to add multiple not existing child elements
  • 时间:2012-05-22 23:10:59
  •  标签:
  • xml
  • xslt

我有一个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>

这很好,只要只缺少一个儿童元素。 但如果两者都丢失了, 只能创建 C1 。 我该如何防止它, 并强制创建 c1 和 c2( 事实上, 大约10 名儿童 )?

Thanks. Jost

最佳回答

我愿意这样做:

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

如果您有较长的子节点列表, 您可以将其放入变量中, 并使用 < code> for- each 而不是单个 < code> 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>

只需在 childformment 变量中添加您需要的所有元素。

( msxsl:node-seet stuff > stuff is Microsoft expecial, 如果您正在使用另一个 XSLT 处理器, 您将需要稍有不同的东西)

问题回答

不要像 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节点存在,则明确生成含有其内容的C1和C2节点。

这里有一个通用的 XSLT 1.0 溶液( 可以使用hinn N to- be 附加元素), 它不使用任何明确的 XSLT 有条件指令或任何 < code> xsl: ementle 指令 :

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




相关问题
how to represent it in dtd?

I have two element action and guid. guid is a required field when action is add. but when action is del it will not appear in file. How to represent this in dtd ?

.Net application configuration add xml-data

I need to add xml-content to my application configuration file. Is there a way to add it directly to the appSettings section or do I need to implement a configSection? Is it possible to add the xml ...

XStream serializing collections

I have a class structure that I would like to serialize with Xstream. The root class contains a collection of other objects (of varying types). I would like to only serialize part of the objects that ...

MS Word splits words in its XML format

I have a Word 2003 document saved as a XML in WordProcessingML format. It contains few placeholders which will be dynamically replaced by an appropriate content. But, the problem is that Word ...

Merging an XML file with a list of changes

I have two XML files that are generated by another application I have no control over. The first is a settings file, and the second is a list of changes that should be applied to the first. Main ...

How do I check if a node has no siblings?

I have a org.w3c.dom.Node object. I would like to see if it has any other siblings. Here s what I have tried: Node sibling = node.getNextSibling(); if(sibling == null) return true; else ...

Ordering a hash to xml: Rails

I m building an xml document from a hash. The xml attributes need to be in order. How can this be accomplished? hash.to_xml