使用XSLT打印包含xml文档属性的元素列表

时间:2011-10-31 19:59:28

标签: xml xslt

我需要解决一个奇怪的问题。我需要一个XSLT样式表,它将打印具有未知结构的xml文档的元素列表及其属性。经过多次尝试,我设法创造了这样的东西:

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

<xsl:template match="/">
<HTML>
<title></title>
<body>  

<xsl:call-template name="recurs">
<xsl:with-param name="nextnodes" select="child::*" />
</xsl:call-template>

</body>
</HTML>
</xsl:template>

<xsl:template name="recurs">
<xsl:param name="nextnodes" />
<xsl:for-each select="$nextnodes">
<xsl:if test="not(name(current())=name(following::*)) and  not(name(current())=name(following::*/descendant::*)) ">
    Element <b><xsl:value-of select="name(current())" /></b> has attributes <text> </text>
    <xsl:for-each select="@*">
    <xsl:if test="position()=last()">
    <b><xsl:value-of select="name(current())" /><text>.</text></b>
    </xsl:if>
    <xsl:if test="position()!=last()">
        <b><xsl:value-of select="name(current())" /><text>,  </text></b>
    </xsl:if>
    </xsl:for-each>
    <br /><br />
</xsl:if>
<xsl:call-template name="recurs">
    <xsl:with-param name="nextnodes" select="child::*" />
</xsl:call-template>

</xsl:for-each> 
</xsl:template>

</xsl:stylesheet>

对于这样的测试用例,当元素书再次出现在其他元素中时,它可以正常工作:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="task3_4a.xsl"?>
<catalog subnodes="2">

<cities country="England">
<city name="London" region="London" population="10000" />
<city name="New South Wales" region="Wales" population="800000" />

</cities> 

<articles country="USA">
<article name="My lovely country" src="art1.txt" />
<article name="Places to visit" src="art2.txt" />
<article name="Article 3" src="art3.txt" />
</articles>

<books>
<book title="Warhammer">
</book>
<book title="We fought for truth"> 
</book>
</books>

<scientifics  atr = " ">
<book title="Warhammer">
</book> 
</scientifics>
</catalog>

但是当我尝试另一个测试时,如果书中有元素文章,则无法正确管理xml:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="task3_4a.xsl"?>
<catalog subnodes="2">

<cities country="England">
<city name="London" region="London" population="10000" />
<city name="New South Wales" region="Wales" population="800000" />

</cities> 

<articles country="USA">
<article name="My lovely country" src="art1.txt" />
<article name="Places to visit" src="art2.txt" />
<article name="Article 3" src="art3.txt" />
</articles>

<books>
<book title="Warhammer">
<article name="My lovely country" src="art1.txt" /> 
</book>
<book title="We fought for truth"> 
<article name="My lovely country" src="art1.txt" /> 
</book>
</books>

<scientifics  atr = " ">
<book title="Warhammer">

<article name="My lovely country" src="art1.txt" /> 
</book> 

</scientifics>

</catalog>

输出现在包含字符串“元素文章具有属性名称,src”。 3次。我不知道如何解决它......

2 个答案:

答案 0 :(得分:2)

<强>予。这是一个非常简短的XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
    <xsl:for-each-group select="//*"
         group-by="string-join((name(), @*/name()), '|')">
      <xsl:sort select="name()"/>

      <p>
        Element <b><xsl:sequence select="name()"/></b>
        has attributes: <xsl:value-of select="@*/name()" separator=", "/>
      </p>
  </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<catalog subnodes="2">
    <cities country="England">
        <city name="London" region="London" population="10000" />
        <city name="New South Wales" region="Wales" population="800000" />
    </cities>
    <articles country="USA">
        <article name="My lovely country" src="art1.txt" />
        <article name="Places to visit" src="art2.txt" />
        <article name="Article 3" src="art3.txt" />
    </articles>
    <books>
        <book title="Warhammer">
            <article name="My lovely country" src="art1.txt" />
        </book>
        <book title="We fought for truth">
            <article name="My lovely country" src="art1.txt" />
        </book>
    </books>
    <scientifics  atr = " ">
        <book title="Warhammer">
            <article name="My lovely country" src="art1.txt" />
        </book>
    </scientifics>
</catalog>

产生了想要的正确结果

<p>
        Element <b>article</b>
        has attributes: name, src</p>
<p>
        Element <b>articles</b>
        has attributes: country</p>
<p>
        Element <b>book</b>
        has attributes: title</p>
<p>
        Element <b>books</b>
        has attributes: </p>
<p>
        Element <b>catalog</b>
        has attributes: subnodes</p>
<p>
        Element <b>cities</b>
        has attributes: country</p>
<p>
        Element <b>city</b>
        has attributes: name, region, population</p>
<p>
        Element <b>scientifics</b>
        has attributes: atr</p>

,并在浏览器中显示为

        元素文章         有属性:name,src

        元素文章         有属性:国家

        元素         有属性:标题

        元素书籍         有属性:

        元素目录         有属性:子节点

        元素城市         有属性:国家

        元素城市         具有属性:名称,地区,人口

        元素科学         有属性:atr

<强> II。 XSLT 1.0(两次通过)解决方案:

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

 <xsl:key name="kElByNameandAttrs" match="*"
  use="concat(name(), '|', @_____attribs)"/>

 <xsl:variable name="vrtfPass1">
  <xsl:apply-templates/>
 </xsl:variable>

 <xsl:template match="*">
  <xsl:copy>
   <xsl:attribute name="_____attribs">
     <xsl:for-each select="@*">
       <xsl:sort select="name()"/>

       <xsl:value-of select="concat(name(), ' ')"/>
     </xsl:for-each>
   </xsl:attribute>

   <xsl:apply-templates select="*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
   <xsl:apply-templates mode="pass2" select=
   "ext:node-set($vrtfPass1)//*
          [generate-id()
          =
           generate-id(key('kElByNameandAttrs',
                           concat(name(),
                                  '|',
                                  @_____attribs)
                           )
                            [1])
           ]"
   >
    <xsl:sort select="name()"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="*" mode="pass2">
  <p>
        Element <b><xsl:value-of select="name()"/></b>
        has attributes: <xsl:value-of select="@_____attribs"/></p>
 </xsl:template>

</xsl:stylesheet>

当在同一个XML文档(上面)上应用此XSLT 1.0转换时,再次生成所需的正确结果

<p>
        Element <b>article</b>
        has attributes: name src </p>
<p>
        Element <b>articles</b>
        has attributes: country </p>
<p>
        Element <b>book</b>
        has attributes: title </p>
<p>
        Element <b>books</b>
        has attributes: </p>
<p>
        Element <b>catalog</b>
        has attributes: subnodes </p>
<p>
        Element <b>cities</b>
        has attributes: country </p>
<p>
        Element <b>city</b>
        has attributes: name population region </p>
<p>
        Element <b>scientifics</b>
        has attributes: atr </p>

答案 1 :(得分:0)

您遇到的一个问题是使用此XPath

<xsl:if test="not(name(current())=name(following::*)) ...

使用轴以下:: 将返回多个节点,但应用 name()函数将只获取第一个节点的名称。

因此,而不是XSLT中的以下行&gt; ...

<xsl:if test="not(name(current())=name(following::*)) and  not(name(current())=name(following::*/descendant::*)) ">  

请尝试使用以下行替换它......

<xsl:if test="not(following::*[name() = name(current())])">

即没有跟随节点(在层次结构的任何级别中)与当前节点名称不同。

执行此操作时,将输出以下内容:

<HTML>
<title></title>
<body>
Element <b>catalog</b> has attributes <text></text><b>subnodes<text>.</text></b><br><br>
Element <b>cities</b> has attributes <text></text><b>country<text>.</text></b><br><br>
Element <b>city</b> has attributes <text></text><b>name<text>,  </text></b><b>region<text>,  </text></b><b>population<text>.</text></b><br><br>
Element <b>articles</b> has attributes <text></text><b>country<text>.</text></b><br><br>
Element <b>books</b> has attributes <text></text><br><br>
Element <b>scientifics</b> has attributes <text></text><b>atr<text>.</text></b><br><br>
Element <b>book</b> has attributes <text></text><b>title<text>.</text></b><br><br>
Element <b>article</b> has attributes <text></text><b>name<text>,  </text></b><b>src<text>.</text></b><br><br></body>
</HTML>

当然,当两个具有相同名称的元素具有不同属性时,这并不能解决匹配问题,但它应该可以解决您文章出现多次的直接问题。

相关问题