使用XSLT的XML到XML(删除,添加,更改)

时间:2012-07-31 04:34:52

标签: xml xslt xhtml xslt-1.0

我必须使用XSLT从一个XML(XHTML)文件转换为另一个。转型规则是:

  1. <div id="ta12" class="bl" style="dis:bl">必须替换为<div class="pass" value="50">
  2. id =“t0b”和“t1b”的值必须分别用id =“ta0b8”和“ta3b8”代替。
  3. <input type="radio" name="o0" id="t0"/>必须替换为<input type="radio" name="key0b8" value="0" id="ta0q" class="block" />(同样在文件中)
  4. 输入文件:

        <?xml version="1.0" encoding="utf-8"?>
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
        <meta http-equiv="Content-type" content="text/html;  charset=utf-8" />
        </head>  
        <body>
          <div class="iDev">
          <div id="ta12" class="bl" style="dis:bl"></div>
    
            <div class="q">
              <div id="t0b" class="block">1<span style="color">TEXT1</span>
              </div><br />
              T <input type="radio" name="o0" id="t0"/> 
              F <input type="radio" name="op0" id="f0"/>
              <div id="sfb"></div>
            </div><br />
    
            <div class="q">
              <div id="t1b" class="block">2<span style="color">TEXT2</span>
              </div><br />
              T <input type="radio" name="o1" id="t1" /> 
              F <input type="radio" name="op1" id="f1" />
              <div id="sfb"></div>
            </div>
          </div>
        </body>
        </html>
    

    输出文件:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html;  charset=utf-8" />
    </head>
    <body>
      <div class="iDev">
      <div class="pass" value="50"></div>
    
        <div class="q">
          <div id="ta0b8" class="block">1<span style="color">TEXT1</span>
          </div><br />
          T<input type="radio" name="key0b8" value="0" id="ta0q" />
          F<input type="radio" name="key0b8" value="1" id="ta1q" />
          <div id="sfb"></div>
        </div><br />
    
        <div class="q">
          <div id="ta3b8" class="block">2 <span style="color">TEXT2</span>
          </div><br />
          T<input type="radio" name="key3b8" value="0" id="ta0q3" />
          F<input type="radio" name="key3b8" value="1" id="ta1q3" />
          <div id="sfb"></div>
        </div>
      </div>
    </body>
    </html>
    

    在我的XSLT中,我创建了一个包含整个输入文件的身份模板,然后我尝试进行必要的修改。我能够通过 -

    完成第一项任务
    <xsl:template match="xhtml:div[@id='ta12']">
      <xsl:attribute name="class">pa</xsl:attribute>
      <xsl:attribute name="value">10</xsl:attribute>
    </xsl:template>
    

    在输出中,它会生成所需的Div标记,但会删除<div class="iDev">标记。谁能告诉我从给定输入产生所需输出的解决方案。谢谢你!

1 个答案:

答案 0 :(得分:2)

我只是要解决你的第一条规则,因为这似乎是你问题的焦点。如果您需要有关规则2和规则3的帮助,请提出单独的问题。

通常,XSLT 1.0复制元素(非深层)的解决方案模式如下所示。非深度,我的意思是删除任何子节点。

清单1

<xsl:template match="some-element-pattern">
  <xsl:copy>
   <xsl:copy-of select="@*" />
   <xsl:attribute name="my-attrib-to-set">value-to-set</xsl:attribute>
  </xsl:copy>
</xsl:template>

或者,您可以将xsl:copy-of替换为xsl:apply-templates,如果有其他属性处理的可能性,则直接复制。 xsl:apply-templates是更通用的形式。

因此,将此解决方案模式应用于您的案例,您想要的模板是......

清单2

<xsl:template match="xhtml:div[@id='ta12']">
  <xsl:copy>
   <xsl:copy-of select="@*" />
   <xsl:attribute name="class">pa</xsl:attribute>
   <xsl:attribute name="value">10</xsl:attribute>
  </xsl:copy>
</xsl:template>

NB。在以前的解决方案中,我可能已经给你这个效率低下的模板......

清单3

<xsl:template match="xhtml:div[@id='ta12']">
  <xsl:copy>
   <xsl:apply-templates select="@*[not(@class)]" />
   <xsl:attribute name="class">pa</xsl:attribute>
  </xsl:copy>
</xsl:template>

我现在意识到这是错误的。谓词not(@class)是无意义的并且总是返回true,因为当焦点项是属性时,属性:: axis总是返回一个空序列。列表3背后的思想是在匹配的输入div元素具有class属性的情况下消除class属性的无关处理。如果你真的想在清单2中获得这种效率,那么在XSLT 1.0中,你可以像清单4一样,但是代码有点丑陋,而且我不确定它是否值得。

清单4

<xsl:template match="xhtml:div[@id='ta12']">
  <xsl:copy>
   <xsl:apply-templates select="@*[local-name()!='class']
                                  [local-name()!='value']" />
   <xsl:attribute name="class">pa</xsl:attribute>
   <xsl:attribute name="value">10</xsl:attribute>
  </xsl:copy>
</xsl:template>

清单4仅适用于null名称空间中的类和值。如果有问题的属性位于命名空间中,则需要进行一些更改。

这是最后的选择。如果你准备牺牲xsl:copy的通用性并希望吮吸属性值模板的多汁骨髓,你可以使用清单5.在清单5中,你可以用属性值模板替换'pa'和'va' , 按要求。此解决方案的另一个缺点是,现在必须(而不仅仅是效率度量)确保在子xsl:apply-templates中不处理@class和@value属性,否则它们将覆盖预期的文字值。

清单5

<xsl:template match="xhtml:div[@id='ta12']">
  <xhtml:div class="pa" value="va">
   <xsl:apply-templates select="@*[local-name()!='class']
                                  [local-name()!='value']" />
  </xhtml:div>
</xsl:template>

最后,我知道你只对XSLT 1.0感兴趣,但为了一点乐趣,我将提到XSLT 2.0解决方案的一般模式。这在清单6中显示。

清单6

<xsl:template match="some-element-pattern">
  <xsl:copy>
   <xsl:apply-templates select="@* except @my-attrib-to-set" />
   <xsl:attribute name="my-attrib-to-set">value-to-set</xsl:attribute>
  </xsl:copy>
</xsl:template>