如何正确获取属性名称及其值? [英] How to get attribute name and its value properly?

查看:116
本文介绍了如何正确获取属性名称及其值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

输入:

 <?xml version =1.0encoding =utf-8?> 
< Software>
< MS version =5.2.3.1/>
< Java version =5.1.0.29/>
< Oracle id =Aversion =1.0.1.11/>
< SQL ID =Pversion =1.0.1.11/>
< / Software>

XSLT:

 <?xml version =1.0encoding =utf-8?> 
< xsl:output method =xmlindent =yes/>
< xsl:template match =/>
< table>
< tr>
< xsl:for-each select =// * [1]>
< xsl:for-each select =@ *>
< td>
< xsl:value-of select =name()/>
< / td>
< / xsl:for-each>
< / xsl:for-each>
< / tr>
< xsl:for-each select =// *>
< tr>
< xsl:value-of select =local-name()/> ::
< td>
< xsl:value-of select =。/>
< / td>
< / xsl:for-each>
< / tr>
< / xsl:for-each>
< / table>
< / xsl:template>
< / xsl:stylesheet>

输出:



目前输出[错误]:

这个脚本给出的输出没有列名
id。在id(不可见)列中添加了一些版本列值作为
,节点中没有属性名称标识。例如。 MS节点仅具有版本
属性,因此输出结果在id列中添加了版本信息。
请输出一次,可能保存并检查html以便正确理解。

 < table> 
< tr>
< td />
< td>
< td>版本< / td>
< / td>
< / tr>
< tr>
< td>软件::
< / td>
< / tr>
< tr>
< td> MS ::
< td> 5.2.3.1< / td>< / td>
< / tr>
< tr>
< td> Java ::
< td> 5.1.0.29< / td>< / td>
< / tr>
< tr>
< td> Oracle ::
< td> A< / td>< td> 1.0.1.11< / td>< / td>
< / tr>
< tr>
< td> SQL ::
< td> P< / td>< td> 1.0.1.11< / td>< / td>
< / tr>
< / table>

预期输出:

每个属性都作为列名/标题和所有列
有自己的值。注意:作为列名称
的属性MS,JAVA等不应该被硬编码,因为属性的数量可能会在运行时发生变化。

 <!DOCTYPE HTML PUBLIC -  // W3C // DTD HTML 4.0 Transitional // EN> 
< html>
< head>
< title>< / title>
< / head>
< body>

< table>
< tr>
< td />
< td>
id< td>版本< / td>
< / td>
< / tr>
< tr>
< td> MS ::< / td>
< td>不存在< / td>< td> 5.2.3.1< / td>
< / tr>
< tr>
< td> Java ::< / td>
< td>不存在< / td>< td> 5.1.0.29< / td>
< / tr>
< tr>
< td> Oracle ::< / td>
< td> A< / td>< td> 1.0.1.11< / td>
< / tr>
< tr>
< td> SQL ::< / td>
< td> P< / td>< td> 1.0.1.11< / td>
< / tr>
< / table>
< / body>
< / html>


解决方案

如果您希望为每种可能的情况输出一列属性名称,而不是仅限于 id version ,然后(在XSLT 1.0中)可以使用名为Muenchian Grouping的技术来获取不同的属性名称。



首先定义一个按键,用它们的名字查找属性

 < xsl:key name =columnsmatch =@ *use =local-name()/> 

然后,为了得到不同的名称(或者说,获得每个不同名称的第一个匹配项),你可以像这样定义一个变量:

 < xsl:variable name =columnsselect =// @ * [generate -id()= generate-id(key('columns',local-name())[1])]/> 

然后,要输出列标题,您可以迭代这个变量

 < xsl:for-each select =$ columns> 
< xsl:sort select =local-name()/>
< td>< xsl:value-of select =local-name()/>< / td>
< / xsl:for-each>

对于每一行,您都会采取类似的方法。假设你定位在一个子元素上,你可以首先定义一个包含当前元素属性的变量。然后,您将再次遍历变量,并输出当前元素的相应属性的值

 < xsl:variable name =attributesselect =@ */> 
< xsl:for-each select =$ columns>
< xsl:sort select =local-name()/>
< td>< xsl:value-of select =$ attributes [local-name()= local-name(current())]/>< / td>
< / xsl:for-each>

试试这个XSLT

 < xsl:stylesheet version =1.0xmlns:xsl =http://www.w3.org/1999/XSL/Transform> 
< xsl:output omit-xml-declaration =yesindent =yes/>
< xsl:template match =软件>
< table>
< tr>
< td>软件< / td>
< xsl:for-each select =$ columns>
< xsl:sort select =local-name()/>
< td>< xsl:value-of select =local-name()/>< / td>
< / xsl:for-each>
< / tr>
< xsl:apply-templates select =*/>
< / table>
< / xsl:template>

< xsl:template match =Software / *>
< tr>
< td>< xsl:value-of select =local-name()/>< / td>
< xsl:for-each select =$ columns>
< xsl:sort select =local-name()/>
< td>< xsl:value-of select =$ attributes [local-name()= local-name(current())]/>< / td>
< / xsl:for-each>
< / tr>
< / xsl:template>
< / xsl:stylesheet>

这应该输出以下内容:

 <表> 
< tr>
< td>软件< / td>
< td> id< / td>
< td>版本< / td>
< / tr>
< tr>
< td> MS< / td>
< td />
< td> 5.2.3.1< / td>
< / tr>
< tr>
< td> Java< / td>
< td />
< td> 5.1.0.29< / td>
< / tr>
< tr>
< td> Oracle< / td>
< td> A< / td>
< td> 1.0.1.11< / td>
< / tr>
< tr>
< td> SQL< / td>
< td> P< / td>
< td> 1.0.1.11< / td>
< / tr>
< / table>

请注意,为了简洁起见,我没有在代码中输出Not exists属性不存在。但它应该很简单,为此添加一个检查。 (只需将值存储在一个变量中,并使用 xsl:choose )编辑:如果您想限制属性对于 Software 元素,请尝试更改此键:

 < xsl:key name = columnsmatch =Software / * / @ *use =local-name()/> 


Input:

<?xml version="1.0" encoding="utf-8" ?>
<Software>
    <MS version="5.2.3.1"/>
    <Java version="5.1.0.29" />
    <Oracle id="A" version="1.0.1.11" />
    <SQL id="P" version="1.0.1.11" />  
</Software>

XSLT:

   <?xml version="1.0" encoding="utf-8"?>
<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="/">
    <table>
      <tr>
        <xsl:for-each select="//*[1]">
          <xsl:for-each select="@*">
            <td>
              <xsl:value-of select="name()"/>
            </td>
          </xsl:for-each>
        </xsl:for-each>
      </tr>
      <xsl:for-each select="//*">
        <tr>
          <xsl:value-of select="local-name()"/> ::
          <xsl:for-each select="@*">
            <td>
              <xsl:value-of select="."/>
            </td>
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

Output:

Current output [wrong]:

This script gives output without column name "id". Some "version" column value added in "id(not visible)" column as there is no attribute name id in node. eg. MS node has version attribute only hence output result added version info in "id" column. Please go through output once, possibly save and check in html for proper understanding.

 <table>
  <tr>
    <td/>
    <td>
      <td>version</td>
    </td>
  </tr>
  <tr>
    <td>Software ::
              </td>
  </tr>
  <tr>
    <td>MS ::
              <td>5.2.3.1</td></td>
  </tr>
  <tr>
    <td>Java ::
              <td>5.1.0.29</td></td>
  </tr>
  <tr>
    <td>Oracle ::
              <td>A</td><td>1.0.1.11</td></td>
  </tr>
  <tr>
    <td>SQL ::
              <td>P</td><td>1.0.1.11</td></td>
  </tr>
</table>

Expected output:

Every attribute as columnname/header and all column have their own value. NOTE: Attributes MS, JAVA, etc as column Name should not be hard coded because the number of attributes may change on runtime.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title></title>
    </head>
    <body>

<table>
  <tr>
    <td/>
    <td>
        id<td>version</td>
    </td>
  </tr>
  <tr>
    <td>MS ::</td>
              <td>Not exist</td><td>5.2.3.1</td>
  </tr>
  <tr>
    <td>Java ::</td>
              <td>Not exist</td><td>5.1.0.29</td>
  </tr>
  <tr>
    <td>Oracle ::</td>
              <td>A</td><td>1.0.1.11</td>
  </tr>
  <tr>
    <td>SQL ::</td>
              <td>P</td><td>1.0.1.11</td>
  </tr>
</table>    
    </body>
</html>

解决方案

If you are looking to output one column for each possible attribute name, and not restrict it to just id and version, then (in XSLT 1.0) you could make use of a technique called Muenchian Grouping to get the distinct attribute names.

First define a key to look up the attributes by their name

<xsl:key name="columns" match="@*" use="local-name()" />

Then, to get the distinct ones (or rather, get the first occurrence of each distinct name), you can define a variable like so

<xsl:variable name="columns" select="//@*[generate-id() = generate-id(key('columns', local-name())[1])]" />

Then, to output the column headers, you can just iterate over this variable

  <xsl:for-each select="$columns">
     <xsl:sort select="local-name()" />
     <td><xsl:value-of select="local-name()" /></td>
  </xsl:for-each>

For each row, you would take a similar approach. Assuming you were positioned on a child element, you could first define a variable that contains the attributes of the current element. Then you would iterate over the columns variable again, and output the value of the corresponding attribute for the current element

  <xsl:variable name="attributes" select="@*" />
  <xsl:for-each select="$columns">
     <xsl:sort select="local-name()" />
     <td><xsl:value-of select="$attributes[local-name() = local-name(current())]" /></td>
  </xsl:for-each>

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output omit-xml-declaration="yes" indent="yes" />
   <xsl:key name="columns" match="@*" use="local-name()" />
   <xsl:variable name="columns" select="//@*[generate-id() = generate-id(key('columns', local-name())[1])]" />
   <xsl:template match="Software">
      <table>
      <tr>
      <td>Software</td>
      <xsl:for-each select="$columns">
         <xsl:sort select="local-name()" />
         <td><xsl:value-of select="local-name()" /></td>
      </xsl:for-each>
      </tr>
      <xsl:apply-templates select="*" />
      </table>
   </xsl:template>

   <xsl:template match="Software/*">
      <tr>
      <td><xsl:value-of select="local-name()" /></td>
      <xsl:variable name="attributes" select="@*" />
      <xsl:for-each select="$columns">
         <xsl:sort select="local-name()" />
         <td><xsl:value-of select="$attributes[local-name() = local-name(current())]" /></td>
      </xsl:for-each>
      </tr>
   </xsl:template>
</xsl:stylesheet>

This should output the following

<table>
  <tr>
    <td>Software</td>
    <td>id</td>
    <td>version</td>
  </tr>
  <tr>
    <td>MS</td>
    <td/>
    <td>5.2.3.1</td>
  </tr>
  <tr>
    <td>Java</td>
    <td/>
    <td>5.1.0.29</td>
  </tr>
  <tr>
    <td>Oracle</td>
    <td>A</td>
    <td>1.0.1.11</td>
  </tr>
  <tr>
    <td>SQL</td>
    <td>P</td>
    <td>1.0.1.11</td>
  </tr>
</table>

Note, for brevity, I have not included code to output "Not exists" in the case where the attribute does not exist. But it should be simple enough to add a check for this. (Just store the value in a variable, and use an xsl:choose)

EDIT: If you want to restrict the attributes to specifically be for Software elements too, try changing the key to this:

<xsl:key name="columns" match="Software/*/@*" use="local-name()" />

这篇关于如何正确获取属性名称及其值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆