Как работать с пространствами имен XML - PullRequest
2 голосов
/ 31 мая 2011

У меня такое ощущение, что этот вопрос довольно простой, но прошло много лет с тех пор, как я сделал xslt, так что, может быть, кто-то может помочь?

У меня есть кусок xml, который был сгенерирован классом .net DataContractSerializer, и мне нужно извлечь данные из этого xml с помощью xslt, чтобы в итоге получить некоторый html. Что меня усложняет, так это интенсивное использование пространств имен ...

Фрагмент XML выглядит следующим образом:

<FundDeal xmlns:i="http://www.w3.org/2001/XMLSchema-instance"  xmlns="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal">
    <Id xmlns="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal">DEAL12345</Id>
    <Account xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
        <d2p1:AlternateId i:nil="true"/>
        <d2p1:Designation>XXX</d2p1:Designation>
        <d2p1:Name>QWERTY</d2p1:Name>
        <d2p1:Number>12345678</d2p1:Number>
        <d2p1:Status i:nil="true"/>
    </Account>
    <Agent xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
        <d2p1:Id>54321</d2p1:Id>
        <d2p1:Name>ASDFG</d2p1:Name>
        <d2p1:Status>Active</d2p1:Status>
    </Agent>
    ....
</FundDeal>

Теперь мне нужно преобразовать этот XML-файл через таблицу стилей, и я считаю, что это довольно сложно. Я признаю, что xsl нуждается в собственной ссылке на задействованные пространства имен и может легко извлекать такие вещи, как приведенный выше идентификатор сделки, с помощью следующего xsl:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ms="urn:schemas-microsoft-com:xslt"
    xmlns:grbd="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal"
    xmlns:gbd="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal"
    xmlns:grba="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
    <xsl:output indent="yes" omit-xml-declaration="yes" method="html"/>
    <xsl:template match="/">
      <html>
        <head>
          <!-- some styles here -->
        </head>
        <body>
          <table cellpadding="5" cellspacing="5" border="0">
            <tr>
              <td class="SectionTitle" colspan="2">
                <xsl:text>Deal Cancellation Notification - </xsl:text>
                <xsl:value-of select="//ggbd:Id"/>
              </td>
            </tr>
          </table>
        </body>
      </html>
    </xsl:template>
</xsl:stylesheet>   

но я изо всех сил пытаюсь прочитать такие вещи, как имя учетной записи, потому что, похоже, происходит несколько пространств имен.

Может кто-нибудь сказать мне xpath для доступа (а) Имя учетной записи и (б) Имя агента? Я думаю, что, видя, как получить к ним доступ, возможно, я получу доступ ко всему, что мне нужно.

Большое спасибо, Пит

Ответы [ 3 ]

5 голосов
/ 31 мая 2011

Если вы собираетесь работать с XML, стоит задуматься о пространствах имен - как бы больно это ни было.Откладывание вашего понимания только усложнит ситуацию в долгосрочной перспективе.

Не существует «нескольких пространств имен» для имени учетной записи или имени агента: элемент всегда входит в самое большее один Пространство имен.

Большая часть синтаксиса пространства имен, который вы видите, - это просто привязка префиксов пространства имен к именам пространства имен (URI).Поэтому, когда вы видите

xmlns:i="http://www.w3.org/2001/XMLSchema-instance"

, это связывает префикс "i" с URI "http://www.w3.org/2001/XMLSchema-instance",, чтобы более глубокие элементы в документе могли использовать префикс" i "(по сути, как способ сохранения нажатий клавиш).

Если атрибут xmlns указан сам по себе со значением (т.е. вы видите xmlns = "что-то"), это означает, что пространство имен является эффектом для этого элемента и его потомков (если не переопределено другимПространство имен указывается на более глубоком уровне).

Таким образом, в вашем примере документа (который является частью hodge-podge пространства имен) Имя пространства имен корневого элемента FundDeal равно "http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal",, и это такжеслучай для его дочерних элементов Account и Agent (хотя они и определяют привязку пространства имен / префикса, это не влияет на их собственное пространство имен: эта привязка используется их дочерними элементами).

Вы можете указать Пространства имен в своей таблице стилей проще всего, связав свои собственные префиксы («фонд» и «сделка» в приведенном ниже примере) для ссылки на Пространства имен, которые выeed (я добавил немного больше, который, я надеюсь, сделает это немного яснее):


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fund="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal"
  xmlns:deal="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal"
  xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
  <xsl:output indent="yes" omit-xml-declaration="yes" method="html"/>
  <xsl:template match="/">
    <html>
      <head>
        <!-- some styles here -->
      </head>
      <body>
        <table cellpadding="5" cellspacing="5" border="0">
          <tr>
            <td class="SectionTitle" colspan="2">
              <xsl:text>Deal Cancellation Notification - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/deal:Id"/>
              <br/>
              <xsl:text>Account Name - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/fund:Account/d2p1:Name"/>
              <br/>
              <xsl:text>Agent Name - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/fund:Agent/d2p1:Name"/>
            </td>
          </tr>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
2 голосов
/ 31 мая 2011

Это сработает, но это не правильный путь:

 //*[local-name()='Account']/grba:Name

и

 //*[local-name()='Agent']/grba:Name

Глядя лучше на ваш ввод, у вас есть родительские пространства имен. Вам необходимо выбрать правильное пространство имен элемента. Например, Account и Agent находятся в области действия grbd, а Name - в grba. Следуя декларациям пространства имен, вы можете выбрать следующее:

//grbd:Account/grba:Name

или

//grbd:Agent/grba:Name

Это верно для элементов с префиксным пространством имен. В противном случае вы должны выбрать местный. Например, для первого узла Id вам необходимо:

//gbd:Id
1 голос
/ 31 мая 2011
...