【问题标题】:A single XSL to rule them all一个单一的 XSL 来统治它们
【发布时间】:2015-02-26 18:23:40
【问题描述】:

我正在构建一个 XSL 样式表来将多个 XML 文件(每个都有不同的根)转换为一组用于样式的 div,但是我在第一个之后定义的任何模板都有问题,我知道我'我在做一些愚蠢/根本错误的事情,但我不知道它是什么,所以任何建议都将不胜感激。

我很确定之前有人问过这个问题,但经过几个小时的搜索后,我找不到结果。

XML#1:

<domain:create xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd">
  <domain:name>exampledomain.gtld</domain:name>
  <domain:period unit="y">1</domain:period>
  <domain:ns>
    <domain:hostAttr>
      <domain:hostName>ns1.exampledomain.gtld</domain:hostName>
      <domain:hostAddr ip="v4">x.x.x.x</domain:hostAddr> 
      <domain:hostAddr ip="v4">y.y.y.y</domain:hostAddr> 
      <domain:hostAddr ip="v6">ff02::1</domain:hostAddr> 
    </domain:hostAttr>
    <domain:hostAttr>
      <domain:hostName>ns1.otherdomain.gtld</domain:hostName> 
    </domain:hostAttr>
  </domain:ns>
  <domain:registrant>RegistrantID</domain:registrant>
  <domain:contact type="admin">AdminID</domain:contact>
  <domain:contact type="tech">TechID</domain:contact>
  <domain:contact type="billing">BillingID</domain:contact>
  <domain:contact type="reseller">ResellerID</domain:contact>
  <domain:authInfo>
    <domain:pw>TransferPassword</domain:pw>
  </domain:authInfo>
</domain:create>

XML#2

<domain:update xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd">
  <domain:name>exampledomain.gtld</domain:name>
  <domain:add>
    <domain:ns>
      <domain:hostAttr>
        <domain:hostName>ns1.exampledomain.gtld</domain:hostName>
        <domain:hostAddr ip="v4">1.1.1.1</domain:hostAddr>
      </domain:hostAttr>
    </domain:ns>
    <domain:contact type="tech">NewTechID</domain:contact>
    <domain:status s="clientHold">Payment overdue.</domain:status>
  </domain:add>
  <domain:rem>
    <domain:ns>
      <domain:hostAttr>
        <domain:hostName>ns1.otherdomain.gtld</domain:hostName>
      </domain:hostAttr>
    </domain:ns>
    <domain:status s="clientTransferProhibited"/>
  </domain:rem>
  <domain:chg>          
    <domain:registrant>NewRegistrantID</domain:registrant>
    <domain:authInfo>
      <domain:pw>NewPassword</domain:pw>
    </domain:authInfo>
  </domain:chg>
</domain:update>

XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">

<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>

<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="domain:update">
  <div class="action">Domain Update: '<xsl:value-of select="domain:name"/>'</div>
    <div class="attributes">
      <xsl:for-each select="domain:ns/domain:hostAttr">
        <div class="hostname">Nameserver: <xsl:value-of select="domain:hostName"/>
          <xsl:for-each select="domain:hostAddr">
            <div>
              <xsl:attribute name="class"><xsl:value-of select="@ip"/>_address</xsl:attribute>
              IP<xsl:value-of select="@ip"/> Glue: <xsl:value-of select="."/>
            </div>
          </xsl:for-each>
        </div>  
      </xsl:for-each>
    </div>
    <div class="contacts">
      <div class="contact_registrant">Registrant: <xsl:value-of select="domain:registrant"/></div>
      <xsl:for-each select="domain:contact">
        <div>  
          <xsl:attribute name="class">contact_<xsl:value-of select="@type"/></xsl:attribute>
          <xsl:value-of select="concat(translate(substring(@type,1,1), $vLower, $vUpper), substring(@type, 2), substring('', 1 div not(position()=last())))"/>: <xsl:value-of select="."/>
        </div>
      </xsl:for-each>
    </div>
    <div class="password">
</xsl:template>

<xsl:template match="domain:create">
  <div class="action">Domain Create: '<xsl:value-of select="domain:name"/>' for a period of <xsl:value-of select="domain:period"/> <xsl:value-of select="domain:period/@unit"/></div>
    <div class="attributes">
      <xsl:for-each select="domain:ns/domain:hostAttr">
        <div class="hostname">Nameserver: <xsl:value-of select="domain:hostName"/>
          <xsl:for-each select="domain:hostAddr">
            <div>
              <xsl:attribute name="class"><xsl:value-of select="@ip"/>_address</xsl:attribute>
              IP<xsl:value-of select="@ip"/> Glue: <xsl:value-of select="."/>
            </div>
          </xsl:for-each>
        </div>  
      </xsl:for-each>
    </div>
    <div class="contacts">
      <div class="contact_registrant">Registrant: <xsl:value-of select="domain:registrant"/></div>
      <xsl:for-each select="domain:contact">
        <div>
          <xsl:attribute name="class">contact_<xsl:value-of select="@type"/></xsl:attribute>
          <xsl:value-of select="concat(translate(substring(@type,1,1), $vLower, $vUpper), substring(@type, 2), substring('', 1 div not(position()=last())))"/>: <xsl:value-of select="."/>
        </div>
      </xsl:for-each>
    </div>
    <div class="password">
</xsl:template>



</xsl:stylesheet>

使用 XML#1 产生:

exampledomain.gtld 1 ns1.exampledomain.gtld x.x.x.x y.y.y.y ff02::1 ns1.otherdomain.gtld RegistrantID AdminID TechID BillingID ResellerID TransferPassword

但是使用 XML#2 会产生(如预期的那样):

Domain Update: 'exampledomain.gtld'
Registrant:

如果我交换命名模板,那么它就可以工作。

愚蠢更新 我省略了 &lt;div class="Password"&gt; 的结束 &lt;/div&gt; 标签

【问题讨论】:

  • 我调整了返回正确名称()的模板选择器
  • 我正在使用w3schools.com/xsl/… 来测试XSL 翻译
  • 在尝试引入 /domain:update 代码之前,我从头开始构建 XSL 并使其在 &lt;xsl:template match="/domain:create"&gt; 上运行。
  • 结合了 michael.hor257k 和 michael-kay 的建议,以获得更简洁的问题
  • 你的愚蠢不在于省略结束标签,我们都做那种事。你的错误在于你如何解决问题。我的错误也是:我现在应该学会永远不要接受“它不起作用”作为对问题的充分描述。但是,您不知道样式表格式不正确这一事实意味着您没有使用正确的开发工具:这就是问题的根本原因。

标签: xml xslt


【解决方案1】:

此时我失去了你:

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="name() = 'domain:update'">
      <xsl:call-template name="domain_update"/>
    </xsl:when>
    <xsl:otherwise test="name() = 'domain:create'">
      <xsl:call-template name="domain_create"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

您在根节点/ 的上下文中。这个节点没有名字,所以测试:

<xsl:when test="name() = 'domain:update'">

永远返回 true。也许你应该尝试:

<xsl:template match="/*">

改为。

另一件事是&lt;xsl:otherwise&gt; 不能有test 属性。如果要执行另一个测试,则需要使用另一个&lt;xsl:when&gt; 标签。使用&lt;xsl:otherwise&gt; 指定默认结果,以防所有测试都返回false。

另请注意,您可以简单地拥有一个匹配domain:create 的模板和另一个匹配domain:update 的模板,而不是这种冗长的分支。然后一个简单的:

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

会为您完成这项工作。而且你甚至不必在你的样式表中写这个,因为内置的模板规则可以做到这一点。


重要:

我没有深入了解您命名模板的内容,但我怀疑它们也需要彻底修改。但这对于一个问题来说太过分了。

【讨论】:

  • 在其他情况下帮助您,谢谢。还尝试template match="/"domain:updatedomain:create 上的其他模板匹配,但它不起作用
  • @McAnix“不起作用”不是一个很好的问题描述。
  • 如果我切换 &lt;xsl:template match="domain:create"&gt;domain:update 的声明顺序,那么如果我使用 XML#1,您的建议会提供输出,但如果我使用 XML#2 则不会提供输出,反之亦然
  • 这是一个应用于 XML #1 文档的骨架模板示例:xsltransform.net/bdxtqd 这是应用于 XML #2 的 same 模板:xsltransform.net/bdxtqd/1
  • 注意 您的文档如何声明域命名空间存在问题;但那是(还)另一个故事......
【解决方案2】:

“/”指的是文档节点,它是最外层元素节点的父节点。文档节点未命名,所以 name() 返回一个空字符串,所以测试“name() = 'domain:update'”失败,你总是落入“otherwise”分支。

无论如何,这是一个糟糕的测试。通过对 name() 函数的结果进行字符串比较,只有当源文档使用这个特定的命名空间前缀时才匹配。你不应该关心使用什么前缀。

最好按照设计使用的方式使用 XSLT,并匹配模板规则。像这样:

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="domain:update">
  ...
</xsl:template>

<xsl:template match="domain:create">
  ...
</xsl:template>

【讨论】:

  • 试过了,不高兴,它返回的 XML 解析为 HTML
  • ...我还将解析其他命名空间前缀,例如contact:create
  • “解析的 HTML”不是你想要生成的吗?
猜你喜欢
  • 1970-01-01
  • 2014-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 2012-11-23
  • 2013-01-20
  • 1970-01-01
相关资源
最近更新 更多