0

假设我的 XML 文件中有以下代码,我想在行中显示以下信息:creationDate - serviceName - problemCode - Division。

<foi:serviceInfo rdf:ID="SI1">
 <foi:serviceName>Sewer</foi:serviceName>
 <foi:problemCode>SI1</foi:problemCode>
 <foi:division>Water</foi:division>
</foi:serviceInfo>

<foi:serviceInfo rdf:ID="SI2">
 <foi:serviceName>Recycling</foi:serviceName>
 <foi:problemCode>SI2</foi:problemCode>
 <foi:division>Solid Waste</foi:division>
</foi:serviceInfo>

<foi:serviceRequest rdf:ID="R1">
       <foi:creationDate>29 03 2013</foi:creationDate>
       <foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
       <foi:creationDate>29 06 2013</foi:creationDate>
       <foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>

我可以按行显示来自 serviceRequest 的信息,但是,我不知道如何将 foi:servicing 中的资源链接到 serviceInfo 的 ID(以便获取 serviceInfo 中包含的属性,然后显示它)。

4

3 回答 3

1

这是一个有点不优雅的解决方案,并且需要额外的工作来扩展到结构不同的数据集(尽管它适用于您的示例数据集中排列的任意数量的 serviceInfo 和 serviceRequest 元素)。它的优点是它涉及使用应用模板而不是 for-each。使用应用模板是最佳实践。另外,我不知道要使用正确的命名空间,所以我只是做了一些。

这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foi="http://www.foi.com"
xmlns:rdf="http://www.rdf.com"
exclude-result-prefixes="foi rdf"
version="2.0">

<!-- Identity template -->
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:variable name="newLine"><xsl:text>

</xsl:text></xsl:variable>
<xsl:template match="/">
    <xsl:value-of select="$newLine"/><table><xsl:value-of select="$newLine"/>
        <xsl:apply-templates select="//foi:creationDate"/>
    </table><xsl:value-of select="$newLine"/>
</xsl:template>
<xsl:template match="foi:creationDate">
    <xsl:variable name="resourceId" select="replace(../foi:servicing/@rdf:resource,'#','')"/>
    <xsl:message>BAH <xsl:value-of select="$resourceId"/></xsl:message>
    <tr><xsl:value-of select="$newLine"/>
        <td><xsl:apply-templates/></td><xsl:value-of select="$newLine"/>
        <td><xsl:apply-templates select="//foi:serviceName[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
        <td><xsl:apply-templates select="//foi:problemCode[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
        <td><xsl:apply-templates select="//foi:division[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
    </tr><xsl:value-of select="$newLine"/>
</xsl:template>
<xsl:template match="foi:serviceName">
    <xsl:apply-templates select="@* | node()" />
</xsl:template>
<xsl:template match="foi:problemCode">
    <xsl:apply-templates select="@* | node()" />
</xsl:template>
<xsl:template match="foi:division">
    <xsl:apply-templates select="@* | node()" />
</xsl:template>
</xsl:stylesheet>

应用于此 XML 文档时:(注意:我添加了一个根元素)

<root>
<foi:serviceInfo rdf:ID="SI1">
    <foi:serviceName>Sewer</foi:serviceName>
    <foi:problemCode>SI1</foi:problemCode>
    <foi:division>Water</foi:division>
</foi:serviceInfo>
<foi:serviceInfo rdf:ID="SI2">
    <foi:serviceName>Recycling</foi:serviceName>
    <foi:problemCode>SI2</foi:problemCode>
    <foi:division>Solid Waste</foi:division>
</foi:serviceInfo>
<foi:serviceRequest rdf:ID="R1">
    <foi:creationDate>29 03 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
    <foi:creationDate>29 06 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>
</root>

产生所需的结果:

<tr>

<td>29 03 2013</td>

<td>Sewer</td>

<td>SI1</td>

<td>Water</td>

</tr>

<tr>

<td>29 06 2013</td>

<td>Recycling</td>

<td>SI2</td>

<td>Solid Waste</td>

</tr>

</table>

简要说明:

  • 抑制文本节点(文本节点的默认模板是输出它们;我们将通过 XSLT 文件末尾的特定模板输出它们)
  • 处理 foi:creationDate 元素
  • 在处理每个 foi:createDate 元素时,找到其父 rdf:resource 并将该值存储在变量中
  • 然后处理每个适当的元素,通过查看文档中的所有元素(这就是“//”的意思),其父的 rdf:ID 与 rdf:resource 匹配(注意:如果有多个匹配的元素,这将输出多个值标准...您的数据集没有这样的多个元素;* 可能是 [也许应该是] foi:serviceName,但我想说明 * 的含义——选择任何元素并且 [] 中的内容区分哪些元素可以合格)
  • 这也允许您在 serviceName 等元素中有子节点(不仅仅是文本节点)并处理这些节点(尽管现在处理正在复制到结果树)
于 2013-02-02T21:27:01.643 回答
1

这个较短的转换使用 X 引用的键并在表中生成所需的结果:

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

 <xsl:key name="kSIById" match="foi:serviceInfo" use="concat('#',@rdf:ID)"/>

 <xsl:template match="/*">
  <table border="1"><xsl:apply-templates/></table>
 </xsl:template>
 <xsl:template match="/*/*" priority="-1"/>

 <xsl:template match="/*/foi:serviceRequest">
  <tr>
   <td><xsl:apply-templates select="foi:creationDate"/></td>
   <xsl:apply-templates select="key('kSIById', foi:servicing/@rdf:resource)/*"/>
  </tr>
 </xsl:template>

 <xsl:template match="foi:serviceInfo/*">
   <td><xsl:value-of select="."/></td>
 </xsl:template>
</xsl:stylesheet>

在提供的源 XML 上应用时(包装在单个顶部元素中并定义了命名空间):

<root xmlns:foi="some:foi" xmlns:rdf="some:rdf">
  <foi:serviceInfo rdf:ID="SI1">
    <foi:serviceName>Sewer</foi:serviceName>
    <foi:problemCode>SI1</foi:problemCode>
    <foi:division>Water</foi:division>
  </foi:serviceInfo>

  <foi:serviceInfo rdf:ID="SI2">
    <foi:serviceName>Recycling</foi:serviceName>
    <foi:problemCode>SI2</foi:problemCode>
    <foi:division>Solid Waste</foi:division>
  </foi:serviceInfo>

  <foi:serviceRequest rdf:ID="R1">
    <foi:creationDate>29 03 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI1"/>
  </foi:serviceRequest>
  <foi:serviceRequest rdf:ID="R2">
    <foi:creationDate>29 06 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI2"/>
  </foi:serviceRequest>
</root>

产生想要的正确结果:

<table border="1">
   <tr>
      <td>29 03 2013</td>
      <td>Sewer</td>
      <td>SI1</td>
      <td>Water</td>
   </tr>
   <tr>
      <td>29 06 2013</td>
      <td>Recycling</td>
      <td>SI2</td>
      <td>Solid Waste</td>
   </tr>
</table>
于 2013-02-03T16:43:20.233 回答
0

在 XSLT 中交叉引用数据的首选方法是使用<xsl:key>. 以下 XSLT 应该这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:foi="foifoifoi" xmlns:rdf="rdfrdf"
                exclude-result-prefixes="foi rdf">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kService" match="foi:serviceInfo" use="@rdf:ID"/>

  <xsl:template match="/*">
    <div>
      <xsl:apply-templates select="foi:serviceRequest" />
    </div>
  </xsl:template>

  <xsl:template match="foi:serviceRequest">
    <xsl:variable name="referenceId"
                  select="substring(foi:servicing/@rdf:resource, 2)" />
    <xsl:variable name="info" select="key('kService', $referenceId)[1]"/>
    <div>
      <xsl:value-of select="foi:creationDate"/>
      <xsl:apply-templates select="$info/*" />
    </div>
  </xsl:template>

  <xsl:template match="foi:serviceInfo/*">
    <xsl:value-of select="concat(' - ', .)"/>
  </xsl:template>
</xsl:stylesheet>

foi(我必须为and组成命名空间,rdf因为您没有指出它们。请用正确的 URI 替换)。在此 XML 上运行时(添加了根节点):

<root xmlns:foi="foifoifoi" xmlns:rdf="rdfrdf">
  <foi:serviceInfo rdf:ID="SI1">
    <foi:serviceName>Sewer</foi:serviceName>
    <foi:problemCode>SI1</foi:problemCode>
    <foi:division>Water</foi:division>
  </foi:serviceInfo>

  <foi:serviceInfo rdf:ID="SI2">
    <foi:serviceName>Recycling</foi:serviceName>
    <foi:problemCode>SI2</foi:problemCode>
    <foi:division>Solid Waste</foi:division>
  </foi:serviceInfo>

  <foi:serviceRequest rdf:ID="R1">
    <foi:creationDate>29 03 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI1"/>
  </foi:serviceRequest>
  <foi:serviceRequest rdf:ID="R2">
    <foi:creationDate>29 06 2013</foi:creationDate>
    <foi:servicing rdf:resource="#SI2"/>
  </foi:serviceRequest>
</root>

这会产生:

<div>
  <div>29 03 2013 - Sewer - SI1 - Water</div>
  <div>29 06 2013 - Recycling - SI2 - Solid Waste</div>
</div>

要点:

  • 使用 anxsl:key允许foi:serviceInfo通过某个定位ID
  • 使用该key()函数foi:serviceInfo通过 ID 查找相关的。最后[1]的 将其限制为第一场比赛。我不确定是否有可能不止一场比赛,但有吗?
  • 将其任何子级呈现foi:serviceInfo为连字符加元素值的模板。
于 2013-02-03T03:01:09.750 回答