XSLT Почему этот базовый выбор не работает? - PullRequest
2 голосов
/ 20 июня 2011

Я пытаюсь переварить контент из AP Webfeed, но по какой-то причине то, что должно быть очень простым для каждого цикла, дает мне припадки.Каналом является xml utf-8, поступающий из точки доступа с использованием php xsltprocessor и simplexml.

Проблема заключается в том, что я не могу указать целевой узел, на котором хочу выполнить цикл.Сам канал является корневым элементом, который имеет некоторые свойства канала, а затем несколько «вступительных» дочерних статей.У каждого из них есть дочерние свойства записи (например, авторское право), а затем фактическое содержание нитфа (свинец и тело)

Похоже, я смогу просто сделать <xsl:for-each select="feed/entry" />, но если я попытаюсь обратиться к«кормить» или «запись» по имени я ничего не получаю.Я даже не могу сделать <xsl:value-of select="feed/id" /> - как ни странно, я могу заставить // nitf @ version вернуться правильно, но не могу получить его через feed / entry / content / nitf / @ version

Я могу обратитьсянекоторый контент с <xsl:for-each select="//nitf"> для получения тела статьи или любых потомков узла nitf, но не более высоких элементов (например, // entry).Единственный способ получить доступ к содержимому ближе к корню - вложив <xsl:for-each="/*" />, начиная с корня (feed) и детализации, что кажется неправильным.

Если кто-то может указать мне правильное направление,Я ДЕЙСТВИТЕЛЬНО оценил бы это, расстраивая меня, что кое-что, казалось бы, настолько простое, застряло у меня на некоторое время.

Формат:

<feed>
   <id></id>
   <published></published>
   <entry>
      <copyright></copyright>
      <content>
         <nitf>
            <head></head>
            <body></body>
         </nitf>
      </content>
   </entry>
   <entry>
      <content>
         <nitf>
            <head></head>
            <body></body>
         </nitf>
      </content>
   </entry>
</feed>



<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:template match="/">
      <!-- this does loop through nitf -->
      <xsl:for-each select="descendant::*/nitf">
         <nitf_title></nitf_title>
      </xsl:for-each>

      <!-- I want to loop on these instead but this never loops -->
      <xsl:for-each select="descendant::*/entry">
         <entry_title><entry_title>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

Извините, я пытался сократить это такЯ смоделировал источник новостей, пример ниже

<?xml version="1.0" encoding="utf-8" ?>

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" xmlns:apnm="http://ap.org/schemas/03/2005/apnm" xmlns:georss="http://www.georss.org/georss">

  <id>urn:publicid:ap.org:31998</id>    
  <title type="xhtml">    
    <apxh:div xmlns:apxh="http://www.w3.org/1999/xhtml">    
      <apxh:span>AP Online National News</apxh:span>    
    </apxh:div>    
  </title>    
  <apcm:Property Name="FeedProperties">    
    <apcm:Property Name="Entitlement" Id="urn:publicid:ap.org:product:31998" Value="AP Online National News" />    
    <apcm:Property Name="FeedSequencing">
      <apcm:Property Name="sequenceNumber" Id="111835329" />
      <apcm:Property Name="minDateTime" Value="2011-06-20T16:56:08.047Z" />    
    </apcm:Property>    
  </apcm:Property>    
  <updated>2011-06-20T16:56:08.047Z</updated>    
  <author>    
    <name>The Associated Press</name>    
    <uri>http://www.ap.org</uri>    
  </author>    
  <rights></rights>    
  <link rel="self" href="http://syndication.ap.org" />    
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>urn:publicid:ap.org:badf779c9d5246b5acb21430ed2214fb</id>
  <title>APFN-US--Gas Drilling-Chemicals</title>
  <updated>2011-06-20T16:56:08.047Z</updated>
  <published>2011-06-20T16:25:39Z</published>
  <author>
    <name>AP</name>
  </author>
  <rights>Copyright 2011</rights>
  <content type="text/xml">
    <nitf version="-//IPTC//DTD NITF 3.4//EN" change.date="October 18, 2006" change.time="19:30" xmlns="">
      <head>
        <docdata>
          <doc-id regsrc="AP" />
          <date.issue norm="20110620T162539Z" />
          <ed-msg info="Eds: APNewsNow." />
          <doc.rights owner="http://www.ap.org" agent="http://license.icopyright.net" type="none" />
          <doc.copyright holder="AP" year="2011" />
        </docdata>
      </head>
      <body>
        <body.head>
          <hedline>
            <hl1 id="headline">Texas becomes 1st to require fracking disclosure</hl1>
            <hl2 id="originalHeadline">Texas becomes 1st to require fracking disclosure</hl2>
          </hedline>
          <distributor>The Associated Press</distributor>
          <dateline>
            <location>HOUSTON</location>
          </dateline>
        </body.head>
        <body.content>
          <block id="Main">
              <p>HOUSTON (AP) — Texas </p>
            </block>
        </body.content>
        <body.end />
      </body>
    </nitf>
  </content>
  <apcm:ContentMetadata xmlns:apcm="http://ap.org/schemas/03/2005/apcm">
    <apcm:DateLineLocation City="Houston" Country="USA" CountryArea="TX" CountryAreaName="Texas" CountryName="United States" />
    <apcm:Priority Numeric="4" Legacy="r" />
    <apcm:ConsumerReady>TRUE</apcm:ConsumerReady>
    <apcm:DateLine>HOUSTON</apcm:DateLine>
  </apcm:ContentMetadata>
</entry>

<entry xmlns="http://www.w3.org/2005/Atom">
  <id>urn:publicid:ap.org:57582781c3a841a2b9849231a4abdb63</id>
  <title>US--Medicare-Prevention</title>
  <updated>2011-06-20T16:54:57.963Z</updated>
  <published>2011-06-20T16:54:43Z</published>
...

Ответы [ 2 ]

2 голосов
/ 20 июня 2011

В отличие от приведенных выше комментариев, вам фактически не нужно никаких объявлений пространства имен для выбора элемента nitf, который является вашим элементом без пространства имен (xmlns=""). Фактически, вы можете выбрать любой элемент nitf в документе, просто используя //. Например:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
       <xsl:copy-of select="//nitf"/>
    </xsl:template>

</xsl:stylesheet>

Скопирует в выходные данные все узлы типа nitf, независимо от пространства имен, производного их родительского элемента.

Вместо этого в другом пространстве имен entry, то есть xmlns="http://www.w3.org/2005/Atom". Чтобы правильно выбрать этот элемент, вы должны объявить префикс пространства имен в своем документе и использовать его соответствующим образом. Например:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:atom="http://www.w3.org/2005/Atom">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:for-each select="//nitf">
            <!-- iterate on nitf children -->
        </xsl:for-each>

        <xsl:for-each select="//atom:entry">
            <!-- iterate on entry children -->
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Итерирует сначала для детей любого {}:nitf, а затем для детей любого {http://www.w3.org/2005/Atom}:entry.


Почему ваш первый XPath не работает

В первом XPath:

descendant::*/nitf

Вы используете ось для выбора любого nitf. Использование * заставляет XPath выбрать все элементы nitf, потомки элементов в пространстве имен null . НО, у вас нет nitf элемента-потомка пустого пространства имен. nitf является потомком элементов, квалифицированных в пространстве имен http://www.w3.org/2005/Atom uri.

Правильный способ использования оси здесь - после объявления префикса пространства имен для http://www.w3.org/2005/Atom (как в предыдущих примерах):

descendant::atom:*/nitf

или вы также можете использовать нижний уровень:

descendant::node()/nitf

Наконец, самый простой способ (как показано в первом примере выше):

//nitf

Обратите внимание, что эти последние два XPath будут выбирать nitf элементов, потомков элементов, квалифицированных в любом пространстве имен. Поэтому вам следует использовать их, когда вы абсолютно точно знаете свой входной документ и знаете, что делаете.

2 голосов
/ 20 июня 2011

Как указано в комментариях выше, ваша проблема связана с пространствами имен в исходном документе. Например, вы пытаетесь сопоставить элемент с именем «entry», но фактический элемент имеет полное имя {http://www.w3.org/2005/Atom}:entry.

Вы должны переписать свой xpath, чтобы включить префикс префикса пространства имен, а затем сопоставить этот префикс с соответствующим значением. В результате «entry» становится «atom: entry», и некоторый включающий элемент имеет объявление atom как xmlns: atom = "http://www.w3.org/2005/Atom".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...