XSLT:文档分析:如何输出文档内的唯一路径?

发布于 2024-11-02 14:36:06 字数 1756 浏览 0 评论 0原文

为了帮助对 XML 文件进行逆向工程,我使用了如下的 Python SAX 处理程序。 有人可以提供等效的 XSLT 来执行相同的工作吗? 这是一个示例输入文件:

<beatles>
  <beatle>
    <name>
      <first>John</first>
      <last>Lennon</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Paul</first>
      <last>McCartney</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>George</first>
      <last>Harrison</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Ringo</first>
      <last>Starr</last>
    </name>
  </beatle>
</beatles>

因此,其想法是获取所有唯一路径(忽略属性)的列表,以获得编写模板等的基本起点。

from xml.sax.handler import ContentHandler
from xml.sax import make_parser
from xml.sax import SAXParseException

class ShowPaths(ContentHandler):

    def startDocument(self):
        self.unique_paths=[]
        self.current_path=[]


    def startElement(self,name,attrs):
        self.current_path.append(name)
        path="/".join(self.current_path)
        if path not in self.unique_paths:
            self.unique_paths.append(path)

    def endElement(self,name):
        self.current_path.pop();

    def endDocument(self):
        for path in self.unique_paths:
            print path

if __name__=='__main__':
    handler = ShowPaths()
    saxparser = make_parser()
    saxparser.setContentHandler(handler)
    in_f=open("d:\\beatles.xml","r")
    saxparser.parse(in_f)  
    in_f.close()

以及在示例上运行程序的结果:

beatles
beatles/beatle
beatles/beatle/name
beatles/beatle/name/first
beatles/beatle/name/last

To help reverse engineer XML files, I'm using a Python SAX handler as below.
Can somebody provide an equivalent XSLT to perform the same job ?
This is an example input file:

<beatles>
  <beatle>
    <name>
      <first>John</first>
      <last>Lennon</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Paul</first>
      <last>McCartney</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>George</first>
      <last>Harrison</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Ringo</first>
      <last>Starr</last>
    </name>
  </beatle>
</beatles>

So the idea is to get a list of all unique paths (ignoring attributes) to get a basic starting point to writing templates etc.

from xml.sax.handler import ContentHandler
from xml.sax import make_parser
from xml.sax import SAXParseException

class ShowPaths(ContentHandler):

    def startDocument(self):
        self.unique_paths=[]
        self.current_path=[]


    def startElement(self,name,attrs):
        self.current_path.append(name)
        path="/".join(self.current_path)
        if path not in self.unique_paths:
            self.unique_paths.append(path)

    def endElement(self,name):
        self.current_path.pop();

    def endDocument(self):
        for path in self.unique_paths:
            print path

if __name__=='__main__':
    handler = ShowPaths()
    saxparser = make_parser()
    saxparser.setContentHandler(handler)
    in_f=open("d:\\beatles.xml","r")
    saxparser.parse(in_f)  
    in_f.close()

And the result of running the program over the example:

beatles
beatles/beatle
beatles/beatle/name
beatles/beatle/name/first
beatles/beatle/name/last

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无需解释 2024-11-09 14:36:06

所以我们的想法是获取所有的列表
唯一路径(忽略属性)
获得写作的基本起点
模板等

这很容易

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="*">
        <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
        <xsl:text>
</xsl:text>
        <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="*" mode="path">
  <xsl:value-of select="concat('/',name())"/>

  <xsl:variable name="vnumPrecSiblings" select=
        "count(preceding-sibling::*[name()=name(current())])"/>
  <xsl:variable name="vnumFollSiblings" select=
        "count(following-sibling::*[name()=name(current())])"/>

  <xsl:if test="$vnumPrecSiblings or $vnumFollSiblings">
   <xsl:value-of select=
     "concat('[', $vnumPrecSiblings +1, ']')"/>
  </xsl:if>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<beatles>
    <beatle>
        <name>
            <first>John</first>
            <last>Lennon</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>Paul</first>
            <last>McCartney</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>George</first>
            <last>Harrison</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>Ringo</first>
            <last>Starr</last>
        </name>
    </beatle>
</beatles>

生成所需的正确结果:

/beatles
/beatles/beatle[1]
/beatles/beatle[1]/name
/beatles/beatle[1]/name/first
/beatles/beatle[1]/name/last
/beatles/beatle[2]
/beatles/beatle[2]/name
/beatles/beatle[2]/name/first
/beatles/beatle[2]/name/last
/beatles/beatle[3]
/beatles/beatle[3]/name
/beatles/beatle[3]/name/first
/beatles/beatle[3]/name/last
/beatles/beatle[4]
/beatles/beatle[4]/name
/beatles/beatle[4]/name/first
/beatles/beatle[4]/name/last

So the idea is to get a list of all
unique paths (ignoring attributes) to
get a basic starting point to writing
templates etc

This is easy:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="*">
        <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
        <xsl:text>
</xsl:text>
        <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="*" mode="path">
  <xsl:value-of select="concat('/',name())"/>

  <xsl:variable name="vnumPrecSiblings" select=
        "count(preceding-sibling::*[name()=name(current())])"/>
  <xsl:variable name="vnumFollSiblings" select=
        "count(following-sibling::*[name()=name(current())])"/>

  <xsl:if test="$vnumPrecSiblings or $vnumFollSiblings">
   <xsl:value-of select=
     "concat('[', $vnumPrecSiblings +1, ']')"/>
  </xsl:if>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<beatles>
    <beatle>
        <name>
            <first>John</first>
            <last>Lennon</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>Paul</first>
            <last>McCartney</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>George</first>
            <last>Harrison</last>
        </name>
    </beatle>
    <beatle>
        <name>
            <first>Ringo</first>
            <last>Starr</last>
        </name>
    </beatle>
</beatles>

the wanted, correct result is produced:

/beatles
/beatles/beatle[1]
/beatles/beatle[1]/name
/beatles/beatle[1]/name/first
/beatles/beatle[1]/name/last
/beatles/beatle[2]
/beatles/beatle[2]/name
/beatles/beatle[2]/name/first
/beatles/beatle[2]/name/last
/beatles/beatle[3]
/beatles/beatle[3]/name
/beatles/beatle[3]/name/first
/beatles/beatle[3]/name/last
/beatles/beatle[4]
/beatles/beatle[4]/name
/beatles/beatle[4]/name/first
/beatles/beatle[4]/name/last
墨洒年华 2024-11-09 14:36:06

我可能没有抓住要点,但我理解这个问题意味着您想要唯一的命名路径。

因此,从这个 XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="nodeName" match="node()" use="name()"/>

<xsl:template match="//*[not(*)]"/>

<xsl:template match="/">
  <paths>
    <xsl:apply-templates select="//*[not(*)]"/>
  </paths>
</xsl:template>

<xsl:template match="node()[count(. | key('nodeName', name())[1]) = 1]" >
  <xsl:choose>
    <xsl:when test="not(child::*)">
      <path>
        <xsl:apply-templates select="parent::*"/>
        <xsl:value-of select="concat('/', name())"/>
      </path>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="parent::*"/>
      <xsl:value-of select="concat('/', name())"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>

我得到以下输出:

<paths>
  <path>/beatles/beatle/name/first</path>
  <path>/beatles/beatle/name/last</path>
</paths>

I might be missing the point here but I understood the question to mean that you wanted unique named paths.

So from this XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="nodeName" match="node()" use="name()"/>

<xsl:template match="//*[not(*)]"/>

<xsl:template match="/">
  <paths>
    <xsl:apply-templates select="//*[not(*)]"/>
  </paths>
</xsl:template>

<xsl:template match="node()[count(. | key('nodeName', name())[1]) = 1]" >
  <xsl:choose>
    <xsl:when test="not(child::*)">
      <path>
        <xsl:apply-templates select="parent::*"/>
        <xsl:value-of select="concat('/', name())"/>
      </path>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="parent::*"/>
      <xsl:value-of select="concat('/', name())"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>

I get the following output:

<paths>
  <path>/beatles/beatle/name/first</path>
  <path>/beatles/beatle/name/last</path>
</paths>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文