xml - 具有模式属性的 XSLT 1.0 模板

标签 xml xslt xslt-1.0

输入 XML:

<?xml version="1.0" encoding="utf-8"?>
<Root>
   <text>
      <body>
         <head>title1</head>
         <div n="1">
            <head>title2</head>
            <div n="1.1">
               <head>title3</head>
               <p>xyz</p>
               <p>xyz</p>
            </div>
            <div n="1.2">
               <head>title4</head>
               <p>xyz</p>
               <p>xyz</p>
               <div n="1.2.1">
                  <p>xyz</p>
                  <p>xyz</p>
               </div>
            </div>
         </div>
      </body>
   </text>
</Root>

我想为所有 <div> 添加属性“id=1”元素和属性“level=0”到 <div>其中没有<div> child 。

这是我实际的 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

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

<xsl:template match="body//div">
    <xsl:copy>
        <xsl:apply-templates select="node()[not(descendant::div)]" mode="level"/>
        <xsl:apply-templates select="node()[descendant::div]" mode="id"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="body//div[not(descendant::div)]" mode="level">
    <xsl:copy>
        <xsl:for-each select=".">
            <xsl:attribute name="id">1</xsl:attribute>
            <xsl:attribute name="level">0</xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="body//div[descendant::div]" mode="id">
    <xsl:copy>
        <xsl:for-each select=".">
            <xsl:attribute name="id">1</xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

模式为“id”的模板应匹配 <div>具有 <div> 的元素child(添加属性“id”),具有 mode="level"的模板应匹配没有 <div> 的元素child(添加属性“id”和“level”)。但由于某种原因我得到了一些<div> (n=1 和 n=1.2.1 的那些)没有被任何模板处理。

实际输出 XML:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
   <text>
      <body>
         <head>title1</head>
         <div>
            title2
            <div id="1" level="0" n="1.1">
               <head>title3</head>
               <p>xyz</p>
               <p>xyz</p>
            </div>

            <div id="1" n="1.2">
               <head>title4</head>
               <p>xyz</p>
               <p>xyz</p>
               <div>
                  xyz
                  xyz
               </div>
            </div>
         </div>
      </body>
   </text>
</Root>

我很确定我犯了一些奇怪的明显错误(也许是在使用带有模式的模板时?),但到目前为止还没有发现它。任何建议将不胜感激。 谢谢大家。

最佳答案

我不完全确定你为什么要使用模式。下面的解决方案仅使用“通用”模板即可实现您想要的效果。

具有模式的模板专门设计用于多次迭代树,从而访问和处理节点两次或更多次。

作为一项规则,应尽可能少地中断身份转换。这就是为什么下面的样式表匹配

  • div 元素与 div 子元素 (div[div])
  • 没有它们 (div[not(div)]),

应用最小的更改,然后使用apply-templates再次将其余节点返回到身份转换。

注意:这适合您显示的输入 XML。然而,为了使其适用于您的实际输入,您可能必须进行更改

<xsl:template match="div[div]">

<xsl:template match="div[descendant::div]">

取决于您的输入结构。

样式表

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

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

<xsl:template match="div[div]">
  <xsl:copy>
     <xsl:attribute name="id">1</xsl:attribute>
     <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="div[not(div)]">
  <xsl:copy>
     <xsl:attribute name="id">1</xsl:attribute>
     <xsl:attribute name="level">0</xsl:attribute>
     <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="UTF-8"?>
<Root>
 <text>
  <body>
     <head>title1</head>
     <div id="1">
        <head>title2</head>
        <div id="1" level="0">
           <head>title3</head>
           <p>xyz</p>
           <p>xyz</p>
        </div>
        <div id="1">
           <head>title4</head>
           <p>xyz</p>
           <p>xyz</p>
           <div id="1" level="0">
              <p>xyz</p>
              <p>xyz</p>
           </div>
        </div>
     </div>
  </body>
 </text>
</Root>

关于xml - 具有模式属性的 XSLT 1.0 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21139226/

相关文章:

XSLT:根据属性选择节点和属性

xslt - 使用 XSLT 1.0 输出多个 namespace 定义

html - XSL - 对于每个不工作

c# - 通过C#将XPath作为参数传递给XSLT,

java - 在运行时设置 Allure 结果目录

ruby-on-rails - 如何防止构建器模板转义属性值中的 URL?

xslt - 如何在XSLT中检查逻辑相等条件?

xslt - 从最后一个元素中删除逗号

php - 如果达到 maxlength,则删除 SQL 行中的最后一个单词? (PHP)

xml - 使用 XSLT 合并相等的命名空间前缀