Страницы

Поиск по вопросам

понедельник, 3 декабря 2018 г.

как распарсить json

Работаю с wiki api, моя задача получить url страницы по id. Использую retrofit2. Вот запрос с которым я работаю [https://ru.wikipedia.org/w/api.php?&action=query&list=&prop=info&inprop=url&format=json&pageids=2549076|744563|4409887] моя проблема в том, что мне приходит json и я не могу его сериализовать, так как мне POJO конвертирует имена классов в виде цифр из id
{ "batchcomplete": "", "query": { "pages": { "744563": { "pageid": 744563, "ns": 0, "title": "Львовский оперный театр", "contentmodel": "wikitext", "pagelanguage": "ru", "pagelanguagehtmlcode": "ru", "pagelanguagedir": "ltr", "touched": "2017-09-16T20:57:05Z", "lastrevid": 87226524, "length": 14547, "fullurl": "https://ru.wikipedia.org/wiki/%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2%D1%81%D0%BA%D0%B8%D0%B9_%D0%BE%D0%BF%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D1%82%D0%B5%D0%B0%D1%82%D1%80", "editurl": "https://ru.wikipedia.org/w/index.php?title=%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2%D1%81%D0%BA%D0%B8%D0%B9_%D0%BE%D0%BF%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D1%82%D0%B5%D0%B0%D1%82%D1%80&action=edit", "canonicalurl": "https://ru.wikipedia.org/wiki/%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2%D1%81%D0%BA%D0%B8%D0%B9_%D0%BE%D0%BF%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D1%82%D0%B5%D0%B0%D1%82%D1%80" }, "2549076": { "pageid": 2549076, "ns": 0, "title": "Крепость Святой Елисаветы", "contentmodel": "wikitext", "pagelanguage": "ru", "pagelanguagehtmlcode": "ru", "pagelanguagedir": "ltr", "touched": "2017-09-15T05:33:34Z", "lastrevid": 87632281, "length": 5055, "fullurl": "https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B5%D0%BF%D0%BE%D1%81%D1%82%D1%8C_%D0%A1%D0%B2%D1%8F%D1%82%D0%BE%D0%B9_%D0%95%D0%BB%D0%B8%D1%81%D0%B0%D0%B2%D0%B5%D1%82%D1%8B", "editurl": "https://ru.wikipedia.org/w/index.php?title=%D0%9A%D1%80%D0%B5%D0%BF%D0%BE%D1%81%D1%82%D1%8C_%D0%A1%D0%B2%D1%8F%D1%82%D0%BE%D0%B9_%D0%95%D0%BB%D0%B8%D1%81%D0%B0%D0%B2%D0%B5%D1%82%D1%8B&action=edit", "canonicalurl": "https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B5%D0%BF%D0%BE%D1%81%D1%82%D1%8C_%D0%A1%D0%B2%D1%8F%D1%82%D0%BE%D0%B9_%D0%95%D0%BB%D0%B8%D1%81%D0%B0%D0%B2%D0%B5%D1%82%D1%8B" }, "4409887": { "pageid": 4409887, "ns": 0, "title": "Памятник Ленину (Львов)", "contentmodel": "wikitext", "pagelanguage": "ru", "pagelanguagehtmlcode": "ru", "pagelanguagedir": "ltr", "touched": "2017-09-16T16:12:47Z", "lastrevid": 83520554, "length": 6170, "fullurl": "https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D0%BC%D1%8F%D1%82%D0%BD%D0%B8%D0%BA_%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D1%83_(%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2)", "editurl": "https://ru.wikipedia.org/w/index.php?title=%D0%9F%D0%B0%D0%BC%D1%8F%D1%82%D0%BD%D0%B8%D0%BA_%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D1%83_(%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2)&action=edit", "canonicalurl": "https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D0%BC%D1%8F%D1%82%D0%BD%D0%B8%D0%BA_%D0%9B%D0%B5%D0%BD%D0%B8%D0%BD%D1%83_(%D0%9B%D1%8C%D0%B2%D0%BE%D0%B2)" } } }
и я не могу его сериализовать, так как мне POJO конвертирует имена классов в виде цифр из id
public class _4409887 implements Serializable { @SerializedName("pageid") @Expose private Integer pageid; @SerializedName("ns") @Expose private Integer ns; @SerializedName("title") @Expose private String title; @SerializedName("contentmodel")
Такие запросы посылаются каждые 5 секунд и количество id динамическое от 0 до 5. Моя задача распарсить json и получить из него значение "fullurl" Вот мой код
synchronized public List getPagesId() {
WikiApi service = getRetrofit().create(WikiApi.class); Call responseBodyCall = service.getArticleId(Constants.WIKI_ACTION, Constants.WIKI_LIST, Constants.TEMP_COORD, Constants.RADIUS_SEARCH_WIKI, Constants.LIMIT_ARTICLE_WIKI, Constants.JSON); responseBodyCall.enqueue(new Callback() {
@Override public void onResponse(Call call, Response response) { Log.d("+++", "response ok id"); if (response.isSuccessful() && response.body().getQuery().getGeosearch().size() > 0) { geoSearch = response.body().getQuery().getGeosearch(); Log.d("+++", "geoSearch " + geoSearch.size()); getWikiUrl(geoSearch); } }
@Override public void onFailure(Call call, Throwable t) { Log.d("+++", "onFailure result NO"); Log.d("+++", String.valueOf(t)); } }); return geoSearch; } private Retrofit getRetrofit() { Gson gson = new GsonBuilder().create(); return new Retrofit.Builder() .baseUrl(Constants.WIKI_BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); } private void checkStartNewUpdate() { cycleRunnable(); }
synchronized public void getWikiUrl(List geoSearch) {
String [] tmpPagesId = new String[geoSearch.size()]; for (int i = 0; i < geoSearch.size(); i++) { if(i < geoSearch.size() - 1) tmpPagesId[i] = (String.valueOf(geoSearch.get(i).getPageid()) + "|"); else tmpPagesId[i] = (String.valueOf(geoSearch.get(i).getPageid()));
Log.d("+++", "pagesId " + tmpPagesId[i]); }
WikiApi service = getRetrofit().create(WikiApi.class);
Call responseBodyCall = service.getArticle(Constants.WIKI_ACTION, Constants.WIKI_INFO, Constants.WIKI_URL, Constants.JSON, tmpPagesId); responseBodyCall.enqueue(new Callback() {
@Override public void onResponse(Call call, Response response) { Log.d("+++", "response url id "); if(response.isSuccessful()) { try { Log.d("+++", response.body().string()); checkStartNewUpdate(); } catch (IOException e) { e.printStackTrace(); } } }
@Override public void onFailure(Call call, Throwable t) { Log.d("+++", "onFailure result NO"); Log.d("+++", String.valueOf(t)); checkStartNewUpdate(); } });
Вот мой интерфейс
@GET("/w/api.php?") Call getArticle( @Query("action") String action, @Query("prop") String INFO, @Query("inprop") String URL, @Query("format") String JSON, @Query("pageids") String... list);


Ответ

Судя по всему внутри pages у вас ключи объектов являются ID-шниками какими-то и их имена заранее не известны. В этом случае вам надо указать в модели чтобы они представлялись в виде Map - тогда их названия могут быть любыми и обращаться к ним можно будет в коде как к ключам-значениям. Т.е. модель для всего JSON должна как-то так выглядеть:
public class JsonModel { public Map query; }
public class InnerModel { public Integer pageid; public Integer ns; public String title; public String fullUrl; }
И потом обращаться к нужному элементу можно как-то так:
for(InnerModel innerModel: response.query.values()){ System.out.println(innerModel.fullUrl); }

Инициализация одного пула соединений на разные сервлеты Tomcat

Есть веб-приложение, в котором в файле web.xml определены два сервлета. Есть пул соединений c3p0, который, как я понимаю, должен инициализироваться один раз.
НО! Если обратиться к одному сервлету, а потом к другому, то пул будет инициализирован дважды и на каждый сервлет окажется свой пул.
Как это исправить, чтобы пул был общим?
Конфигурация application-context.xml :


Конфигурация сервлета 1:



Конфигурация сервлета 2:


Описание бинов для application-context:
package ru.rusal.mishka.core;
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.eclipse.persistence.jpa.PersistenceProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory; import javax.persistence.ValidationMode; import javax.sql.DataSource; import java.beans.PropertyVetoException; import java.util.Properties;
@Configuration
public class ContextConfiguration {
@Bean public DataSource dataSource( @Qualifier("systemConfiguration") SystemConfiguration systemConfiguration ) throws PropertyVetoException { Properties props = new Properties(); props.setProperty("user", systemConfiguration.getDBConfig().getUser()); props.setProperty("password", systemConfiguration.getDBConfig().getPassword());
final ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("oracle.jdbc.OracleDriver"); dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:DB"); dataSource.setInitialPoolSize(5); dataSource.setMaxPoolSize(20); dataSource.setProperties(props);
return dataSource; }
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory( @Qualifier("dataSource") DataSource ds ) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("MilliService"); factoryBean.setDataSource(ds); factoryBean.setPersistenceProviderClass(PersistenceProvider.class); factoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); factoryBean.setValidationMode(ValidationMode.NONE); factoryBean.setPackagesToScan("ru.milli.app.persistence"); factoryBean.getJpaPropertyMap().put("eclipselink.weaving", Boolean.FALSE.toString()); factoryBean.getJpaPropertyMap().put("eclipselink.allow-zero-id", Boolean.TRUE.toString());
return factoryBean; }
@Bean public JpaTransactionManager transactionManager( @Qualifier("entityManagerFactory") EntityManagerFactory factory ) throws PropertyVetoException { JpaTransactionManager manager = new JpaTransactionManager(); manager.setEntityManagerFactory(factory); return manager; } }
Для сервлетов там обычные rest-сервисы на аннотациях @RestController.
Конфиг web.xml:

mishka
ru.milli.CleanupContextListener
webportal org.springframework.web.servlet.DispatcherServlet
rest org.springframework.web.servlet.DispatcherServlet
rest /rest/*
webportal *.html
webportal /image.jpeg
500 /WEB-INF/jsp/error.jsp
404 /error.html
/WEB-INF/jsp/start.jsp
http://www.springframework.org/tags /WEB-INF/tld/spring.tld http://www.springframework.org/tags/form /WEB-INF/tld/spring-form.tld


Ответ

Проблема в том, что вы создаёте 2 DispatcherServlet, и в оба включаете application-context.xml. Согласно документации
A web application can define any number of DispatcherServlets. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc.
У каждого DispatcherServlet будет свой контекст Spring, а значит, бины для каждого будут создаваться по отдельности. Тег объединяет текущий конфиг с содержимым импортируемого конфига. Получается, в конфиге каждого сервлета будет объявлен свой пул соединений, и при запуске приложения он создастся два раза.
Решить это можно, создав root контекст с бинами, необходимыми всем дочерним контекстам. Делается это при помощи добавления ContextLoaderListener в web.xml
org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:/path/to/application-context.xml
Все бины, определённые в root контексте, будут видны в дочерних (web application) контекстах. При этом дочерний контекст может переопределить бин из родительского контекста (объявив свой бин с таким же id), поэтому включать application-context.xml в конфиг каждого сервлета при такой конфигурации не нужно.

Проблемы с элементом FlowLayoutPanel

Имеются проблемы с элементом FlowLayoutPanel в программе. У меня существует UserControlPanel - так вот этот элемент я в отдельном потоке бесконечно, добавляю в эту FlowLayoutPanel
UserControlPanel panel = new UserControlPanel(a, spisok); flowLayoutPanel1.Controls.Add(panel); flowLayoutPanel1.Controls.SetChildIndex(panel, 0);
Вставляю каждый новый UserControlPanel в начало FlowLayoutPanel, а остальные UserControlPanel сдвигаются вправо и если по горизонтали всё заполнено, переставляются на новую строку. А в случае заполнения вертикали FlowLayoutPanel, у неё появляется скролл.
Т.е. всё работает как надо.
Но проблема вот в чём:
Так вот представим, что скролл находится на самом верху или по середине. И если приложение находится не в актином окне, и я к нему обращусь, кликнув в любую область FlowLayoutPanel, скролл улетает вниз и мне каждый раз приходится крутить его вверх, что бы смотреть что там добавляется в начале.
Как такое лечится ?
UPDATE: Добавил пример проекта https://yadi.sk/d/SOkWH3xL3Qczeh
Каждые 3 секунды добавляется UserConrol в FLP, когда заполняется FLP по вертикали, появляется скролл и если скрыть любой Conrol по спец. кнопке , скролл улетает вниз, а не остаётся на месте и тоже самое происходит, когда кликаю по форме если она неактивна.


Ответ

Для удобства добавления новых элементов на FlowLayoutPanel, подписываемся на событие Control.ControlAdded таким обработчиком:
flowLayoutPanel1_ControlAdded(object sender, ControlEventArgs e) { var flp = (FlowLayoutPanel)sender; flp.Controls.SetChildIndex(e.Control, 0); flp.ScrollControlIntoView(e.Control); }
В отличие от методов Control.Select() и Control.Focus(), которые переключают фокус на выбранный контрол и мешают работать с другими контролами на той же форме, метод ScrollableControl.ScrollControlIntoView(Control) не перехватывает фокус, а только сдвигает скрол так, чтобы переданный в параметре дочерний элемент оказался в видимой области. Поэтому вы можете, например, спокойно печатать в TextBox во время добавления новых элементов.
Данный обработчик будет возвращать скрол в самое верхнее положение, чтобы обеспечить видимость добавленного элемента. Между добавлениями можете крутить его как хотите, хотя если элементы добавляются часто, то из этого мало что получится, но подергать для проверки можно.

Инициализация переменной в SQL

Необходимо инициализировать переменную и присвоить ей значение, которое хранит один из столбцов таблицы. Потом надо проверить, равно ли это значение переменной 11. Пытаюсь сделать таким образом:
CREATE PROCEDURE Functions @codes INT AS DECLARE @ans INT; SET @ans = SELECT [Код ответа] FROM [SofI].[dbo].[Журнал] WHERE [Код сеанса] = @codes AND [Код вопроса] = 11
IF (@ans = 11) exec FunOther
Это наверное глупо, но я не знаю как иначе, даже не знаю как иначе (без использования переменной) проверить условие равенства. Так тоже нельзя:
IF ((SELECT [Код ответа] FROM [SofI].[dbo].[Журнал] WHERE [Код сеанса] = @codes AND [Код вопроса] = 11) = 11)
Как можно сделать проверку?


Ответ

правильный и безопасный синтаксис вашей процедуры будет таким:
CREATE PROCEDURE Functions @codes INT AS DECLARE @ans INT; SET @ans = (SELECT top 1 [Код ответа] FROM [SofI].[dbo].[Журнал] WHERE [Код сеанса] = @codes AND [Код вопроса] = 11);
IF (@ans = 11) exec FunOther
top 1 в селекте нужен для обеспечения нормальной работоспособности, когда после изменения данных таблицы ваш запрос вернет 2 значения.

P.S. Для решения текущей задачи можно было бы воспользоваться следующей конструкцией:
IF EXISTS(SELECT 1 FROM [SofI].[dbo].[Журнал] WHERE [Код сеанса] = @codes AND [Код вопроса] = 11 AND [Код ответа] = 11) exec FunOther

Контроль отключения сопряженного устройства по COM порту

Имеется следующий код.
public static class PortHandler { private static ConnectionType _state; private static SerialPort _port; public static void init() { _state = ConnectionType.DETACHED; Thread serialMonitor = new Thread(SerialMonitor); serialMonitor.IsBackground = true; serialMonitor.Start(); } static void SerialMonitor() { while (true) { switch (_state) { case ConnectionType.DETACHED: scanPorts(); break; case ConnectionType.CONNECTED: FormFunctions.writeLog("Check Port. Size: " + SerialPort.GetPortNames().Length, MessageType.INFO); try { _port.Write(new byte[1] { 0x00 }, 0, 1); } catch (Exception e) { FormFunctions.writeLog("Fault to connect to " + _port.PortName + ". Exception: " + e, MessageType.INFO); _state = ConnectionType.DETACHED; } break; } Thread.Sleep(1000); } } private static void scanPorts() { string[] ports = SerialPort.GetPortNames(); if (ports.Length == 0) { FormFunctions.writeLog("Port list is empty.", MessageType.INFO); return; } foreach (string port in ports) { if (checkSerialPort(port)) { FormFunctions.writeLog("Port connected.", MessageType.SUCCESS); _state = ConnectionType.CONNECTED; break; } } } private static Boolean checkSerialPort(string name) { _port = new SerialPort(name); _port.BaudRate = 9600; _port.Parity = Parity.None; _port.StopBits = StopBits.One; _port.DataBits = 8; _port.Handshake = Handshake.None; _port.PinChanged += new SerialPinChangedEventHandler(SerialPinChangedEventHandler); _port.Open(); byte[] init = new byte[4] { 0xa1, 0xa1, 0xa1, 0xa1 }; _port.Write(init, 0, init.Length); return true; } private static void SerialPinChangedEventHandler(object sender, SerialPinChangedEventArgs e) { FormFunctions.writeLog("Pin Changed Event: " + e, MessageType.SUCCESS); } }
Если закомментировать все стройчки с подключением к порту и отправкой информации, то в логах программы регистрируются все ивенты с подключением/отключением устройства синхронно со звуком в системе. Но стоит создать подключение, то всё работает до (!) эмуляции отвала устройства. Т.е. если я вручную выдёргиваю девайс, то получаю IO Exception на строке _port.Open()
Лог работы программы следующий:
12.12.2017, 11:57:11 [INFO]: Port list is empty. 12.12.2017, 11:57:12 [INFO]: Port list is empty. 12.12.2017, 11:57:13 [INFO]: Port list is empty. 12.12.2017, 11:57:14 [INFO]: Port list is empty. 12.12.2017, 11:57:15 [INFO]: Port list is empty. 12.12.2017, 11:57:16 [INFO]: Port list is empty. 12.12.2017, 11:57:17 [SUCCESS]: Port connected. 12.12.2017, 11:57:18 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:19 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:20 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:21 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:22 [INFO]: Check Port. Size: 1 12.12.2017, 11:57:22 [INFO]: Fault to connect to COM15. Exception: System.IO.IOException: Порт 'COM15' не существует. в System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str) в System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult) в System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout) в System.IO.Ports.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count) в Infrared.common.PortHandler.SerialMonitor() в C:\...\PortHandler.cs:строка 42
Пробовал использовать ивент SerialPinChangedEventHandler, но никакой реакции на него нет. Также пробовал принудительно завершать текущее подключение, но получаю ошибку NPE на функции _port.Close().
Подскажите, где я неправ.
P.S. Или статический класс не подходящий пример решения моей задачи, т.к. Dispose() с ним не работает?
P.S.S. Есть ли смысл реализовать это в инстансе на Singleton?


Ответ

Должно же кому-то пригодиться. Судя из англоязычных форумов, сама Microsoft не даёт никаких гарантий на то, что сама реализация SerialPort() будет работать корректно. Это зависит от многих условностей: тип порта, драйвера, аппаратная реализация (какие каналы задействованы) и прочее, прочее, прочее.
А также, стоит отметить что некоторые функции, например: SerialPort.Close() могут содержать несколько инструкций, которые могут генерировать собственные исключения. Но при этом они завершают, скажем так, начатое.
Моя проблема с "залипанием" соединения на порту при "отвале" устройства (виртуальный COM порт) была решена просто:
if (_port != null) { try { _port.Close(); } catch (Exception e) { // Ignore pointless exception. } _port = null; }
Это необходимо добавлять в catch() блок где находится функция записи в порт. Иными словами, если запись в порт невозможна, то "убиваем не убитое". В итоге, порт освобождается и объект не содержит больше ничего. Что позволяет продолжать мониторинг "реальных" портов в системе и осуществлять повторное подключение по доступности.
Со стороны это выглядит как мега костыль.
P.S. Я сильно ошибался, считая Java самым убогим языком ООП. Каюсь.

Что дает наличие transform: translateZ(0) scale(1, 1) в body

Не первый раз встречаю правило transform: translateZ(0) scale(1, 1), какое применяется к тегу .
Вопрос, что дает данное правило?
Так как у меня от него следующий проблемы: border не всегда прорисовывается в таблице и иногда изображения не прогружаются (случай в Google Chrome). Но! Когда отключаешь это правило, сайт сдвигается(пока еще не понял почему, ведь значения стандартные ИМХО). На сайтах где-то прочитал, что это для того, чтобы мерцания не было ( но может я не правильно понял). Спасибо


Ответ

Без минимального, самодостаточного и воспроизводимого примера вашей конкретной ошибки сложно сказать наверняка.
Обычно translateZ(0) прописывают для того, чтобы отрисовать элементы в GPU еще до того, как анимация началась, чтобы анимация была плавной, без дерганий. tranform не перерисовывает объект, он работают напрямую с GPU памятью, которая использует аппаратное ускорение.
scale(1, 1) увеличивает содержимое блока в 110% от нормы. Скорее всего именно поэтому вы не видите некоторые бордеры, границы содержимого. Ведь они больше ширины блока на 10% и скорее всего просто в него не влезли. Можете попробовать прописать принудительно overflow. Возможно у вас что-то наподобие вот этого:
div { height: 50px; margin: 20px; border: 5px solid red; transform: translateZ(0) scale(1.1); } .one { overflow: hidden } .two { overflow:auto } .three { overflow: visible; } span { height: 50px; display: block; border: 5px solid green; }

1
2
3

В каком виде дизайнер должен передавать верстальщику изображения SVG

Никак не могу найти ответы на некоторые нюансы касаемо svg. Кто должен создавать svg? Допустим есть макет, который необходимо сверстать... Логотипы и иконки не предоставлены дизайнером в svg. Или если есть, то код svg с ошибками. Что должен делать верстальщик в таком случае?
а) Жаловаться дизайнеру/заказчику? b) вставлять png/иконочные шрифты? c) писать сам svg?
Кто пишет код svg от руки, а не рисует? Входит ли это все в обязанности верстальщика/фронтендера (a не дизайнера, например)? В полном ли объеме.
Вот пример кода полученного от дизайнера сделанного в фотошопе


Ответ

Вопрос на самом деле хороший, актуальный, но надо немного под другим углом его задать:
В каком виде дизайнер должен передавать верстальщику изображения SVG.
Какие требования по содержанию кода SVG должны быть предъявлены дизайнеру. Ведь изображение можно рисовать совершенно по разному и многие проблемы верстальщика идут от исходного кода, порою просто невозможно реализовать поставленную задачу.
Например:
иконка нарисована лепкой, а не одиночными линиями, поэтому невозможно будет сделать анимацию. Растровое изображение в векторном формате обернуто в SVG. Поэтому очень затруднительно стилизовать его стилями CSS. Только с применением фильтров.
см. Задать цвет картинке svg в файле со стилями
Изображение в векторном редакторе нормально открывается, а в приложении не попадает в поле видимости. Изображение нарисовано в фотошопе и сохранено плагином в SVG. Код на выходе просто ужасный. Пример Невозможно изменить стили иконки с помощью обычных правил css.
fill, stroke и т.д. К примеру,- стремление дизайнера к оригинальности порой доходит до абсурда. Вместо использования стандартных иконок меньше по весу 1к, типа галочки, он создаёт свой "шедевр" в растровом редакторе и сохраняет в формате base64.
Пример
Конечно, чтобы грамотно предъявить эти требования дизайнеру, необходимо верстальщику освоить начальные знания по SVG самому.